diff --git a/.circleci/config.yml b/.circleci/config.yml index b310100e0..366386c3f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: command: sudo apt-get update -yq && sudo apt install -yq lftp pandoc gvfs emacs - run: name: Deploy to https://staging.organice.200ok.ch - command: 'FTP_USER=${FTP_USER_STAGE} FTP_PASSWD=${FTP_PASSWD_STAGE} ./bin/compile_and_upload.sh' + command: 'FTP_USER=${FTP_USER_STAGE} FTP_PASSWD=${FTP_PASSWD_STAGE} make deploy' - run: name: Deploy documentation to https://staging.organice.200ok.ch/documentation.html command: 'FTP_USER=${FTP_USER_STAGE} FTP_PASSWD=${FTP_PASSWD_STAGE} ./bin/compile_doc_and_upload.sh' diff --git a/.eslintignore b/.eslintignore index 3e2e84b08..498520202 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ build/ +release/ node_modules/ diff --git a/.eslintrc.yml b/.eslintrc.yml index 3393dac66..0e6572c40 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -9,6 +9,7 @@ extends: globals: Atomics: readonly SharedArrayBuffer: readonly + process: readonly parser: babel-eslint parserOptions: ecmaFeatures: diff --git a/.gitignore b/.gitignore index a8fa9f9d2..491104de6 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ yarn-error.log* /documentation.org .eslintcache +/local.mk +/release diff --git a/.nvmrc b/.nvmrc index 0fefb1351..4a4116705 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12.13.1 +12.20.0 diff --git a/.prettierignore b/.prettierignore index 3e2e84b08..498520202 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ build/ +release/ node_modules/ diff --git a/Makefile b/Makefile index d45aacf04..0e3a51f39 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,98 @@ -SHELL = /bin/bash +# ------------------------------------------------------------ +# includes + +-include .ok/credentials.mk +-include local.mk + +# ------------------------------------------------------------ +# variables + +ANDROID_TARGET?=Pixel_3_API_32 + +SHELL:=/bin/bash + +REVISION=$(shell git describe --tags) + +RELEASE_FILES=$(shell find release/ -type f -name '*.js') + +# ------------------------------------------------------------ +# functions -.DEFAULT_GOAL = run +check_defined = \ + $(strip $(foreach 1,$1, \ + $(call __check_defined,$1,$(strip $(value 2))))) +__check_defined = \ + $(if $(value $1),, \ + $(error Undefined $1$(if $2, ($2)))) # ------------------------------------------------------------ # dev +.PHONY: help +help: ## Show this help (default) + @egrep -h '\s##\s' $(MAKEFILE_LIST) | \ + awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m %-30s\033[0m %s\n", $$1, $$2}' + +# This is likely the only case in which make should call yarn. .PHONY: setup -setup: +setup: ## Setup the project yarn install --production=false + make src/lib/headline_filter_parser.js -.PHONY: run -run: setup - yarn start +.PHONY: start +start: setup src +start: ## Run a server that serves organice as PWA + npx react-scripts start .PHONY: test -test: setup - yarn test +test: setup src +test: ## Run the tests + npx react-scripts test --env=jsdom .PHONY: docs -docs: +docs: ## Compile the documentation ./bin/compile_doc.sh .PHONY: deploy-docs deploy-docs: docs +deploy-docs: ## Deploy the documentation ./bin/compile_doc_and_upload.sh + +build: setup src +build: ## Build a production (pre-)build + bin/transient_env_vars.sh bait + npx react-scripts build + +release: build +release: ## Build a release (with proper credentials and build number) + bin/transient_env_vars.sh switch build release + make set-revision + +.PHONY: set-revision +set-revision: $(RELEASE_FILES) +set-revision: ## Set the build revision + for FILE in $?; do sed -i "s/ORGANICE_ROLLING_RELEASE/$(REVISION)/" $$FILE; done + +.PHONY: android +android: release +android: ## Build the android app and run it on $ANDROID_TARGET + npx cap run android --target $(ANDROID_TARGET) + +.PHONY: check-ftp-credentials +check-ftp-credentials: ## Check for FTP credentials + $(call check_defined, FTP_HOST, deployment target) + $(call check_defined, FTP_USER, deployment user) + $(call check_defined, FTP_PASSWD, deployment password) + +.PHONY: deploy +deploy: check-ftp-credentials setup release +deploy: ## Deploy organice as PWA via FTP + cd release && \ + lftp -u${FTP_USER},${FTP_PASSWD} -e "mirror -R ./; bye" ${FTP_HOST} + +# ------------------------------------------------------------ +# internals + +src/lib/headline_filter_parser.js: src/lib/headline_filter_parser.grammar.pegjs + echo '/* eslint-disable */' > $@ + npx pegjs -o - $< >> $@ diff --git a/Procfile b/Procfile index 8ce0321b1..21cc949b0 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: serve build +web: serve release diff --git a/README.org b/README.org index 5f8d110d3..b6fc042e4 100644 --- a/README.org +++ b/README.org @@ -413,7 +413,8 @@ nvm use To install the necessary packages, run: #+BEGIN_SRC shell -yarn install --production=false + npm install -g yarn + yarn install --production=false #+END_SRC *** Setup any of the synchronization back-ends @@ -478,19 +479,19 @@ you can manually generate it with: ./bin/compile_search_parser.sh #+END_SRC -** Testing +** User Acceptance Testing When you're developing a new feature and you want to manually test it, it's best to check it out in a Desktop browser and on your smartphone. This is how you do that: -*** Desktop +*** PWA on Desktop Run the application with =yarn start= which will open organice in your configured default browser. Alternatively, visit =http://localhost:3000= in the browser of your choice. -*** Smartphone +*** PWA on Smartphone There are multiple options on how you can connect from your smartphone to your computer running organice. @@ -528,6 +529,43 @@ ssh -L 3000:localhost:3000 user-dev-machine If you don't have a shell on your phone, you can use a dedicated SSH application (like [[https://www.termius.com/][Terminus]]). +*** Native app on Android + +- Install [[https://developer.android.com/studio#downloads][Android Studio]] +- Follow the [[https://capacitorjs.com/docs/getting-started/environment-setup#android-sdk][Capacitor Guide to setup an Android SDK]] + +#+begin_quote +/:warning:/ Make sure to install the required subpackages. Activate +"Show Package Details" to reveal hidden subpackages. + +At time of writing "Android API 32" does not automatically install the +subpackages "Google APIs Intel x86 Atom_64 System Image" and "Google +Play Intel x86 Atom_64 System Image", which are both required to run +the Emulator on an Intel based machine. + +[[https://raw.githubusercontent.com/200ok-ch/organice/master/images/api_32.png]] +#+end_quote + +- Create a device in Android Studio by running any app + +#+begin_quote +/:monocle_face:/ Theoretically this should not be nescessary, as +Capacitor should be able to create a device to deploy the app to on +the fly. But this didn't work for me. After the device had be run once +by Android Studio, Capacitor was able to start it on its own. +#+end_quote + +- Shut down Android Studio and any running Emulator +- Before run organice as a native app you need to =yarn build= it +- Run organice in the Emulater with =npx cap run android= + +*** TODO Native app on iOS + +#+begin_quote +/:sparkles:/ This is brand new section that wants to be written. +Please check out how to [[#contributions][contribute to organice]]. +#+end_quote + ** Debugging Tests Apart from the popular choice of =console.log=-debugging, it's easy to @@ -575,6 +613,9 @@ merging a pull request to =develop=, code and documentation are automatically deployed to stage. ** Contributions + :PROPERTIES: + :CUSTOM_ID: contributions + :END: Please see our [[https://github.com/200ok-ch/organice/blob/master/CONTRIBUTING.org][contributor guidelines]] and our [[https://github.com/200ok-ch/organice/blob/master/CODE_OF_CONDUCT.md][code of conduct]]. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 000000000..63c86fe30 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,96 @@ +# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore + +# Built application files +*.apk +*.aar +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ +# Uncomment the following line in case you need and you don't have the release build type files in your app +# release/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +# Android Studio 3 in .gitignore file. +.idea/caches +.idea/modules.xml +# Comment next line if keeping position of elements in Navigation Editor is relevant for you +.idea/navEditor.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild +.cxx/ + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + +# Version control +vcs.xml + +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ + +# Android Profiling +*.hprof + +# Cordova plugins for Capacitor +capacitor-cordova-android-plugins + +# Copied web assets +app/src/main/assets/public diff --git a/android/Gemfile b/android/Gemfile new file mode 100644 index 000000000..7a118b49b --- /dev/null +++ b/android/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem "fastlane" diff --git a/android/Gemfile.lock b/android/Gemfile.lock new file mode 100644 index 000000000..62a536f25 --- /dev/null +++ b/android/Gemfile.lock @@ -0,0 +1,218 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + artifactory (3.0.15) + atomos (0.1.3) + aws-eventstream (1.2.0) + aws-partitions (1.598.0) + aws-sdk-core (3.131.1) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.525.0) + aws-sigv4 (~> 1.1) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.57.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.114.0) + aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + colored (1.2) + colored2 (3.1.2) + commander (4.6.0) + highline (~> 2.0.0) + declarative (0.0.20) + digest-crc (0.6.4) + rake (>= 12.0.0, < 14.0.0) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.7.6) + emoji_regex (3.2.3) + excon (0.92.3) + faraday (1.10.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) + http-cookie (~> 1.0.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.6) + fastlane (2.206.2) + CFPropertyList (>= 2.3, < 4.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) + bundler (>= 1.12.0, < 3.0.0) + colored + commander (~> 4.6) + dotenv (>= 2.1.1, < 3.0.0) + emoji_regex (>= 0.1, < 4.0) + excon (>= 0.71.0, < 1.0.0) + faraday (~> 1.0) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 1.0) + fastimage (>= 2.1.0, < 3.0.0) + gh_inspector (>= 1.1.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) + json (< 3.0.0) + jwt (>= 2.1.0, < 3) + mini_magick (>= 4.9.4, < 5.0.0) + multipart-post (~> 2.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) + plist (>= 3.1.0, < 4.0.0) + rubyzip (>= 2.0.0, < 3.0.0) + security (= 0.1.3) + simctl (~> 1.6.3) + terminal-notifier (>= 2.0.0, < 3.0.0) + terminal-table (>= 1.4.5, < 2.0.0) + tty-screen (>= 0.6.3, < 1.0.0) + tty-spinner (>= 0.8.0, < 1.0.0) + word_wrap (~> 1.0.0) + xcodeproj (>= 1.13.0, < 2.0.0) + xcpretty (~> 0.3.0) + xcpretty-travis-formatter (>= 0.0.3) + gh_inspector (1.1.3) + google-apis-androidpublisher_v3 (0.22.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-core (0.5.0) + addressable (~> 2.5, >= 2.5.1) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) + mini_mime (~> 1.0) + representable (~> 3.0) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.11.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-playcustomapp_v1 (0.8.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-storage_v1 (0.15.0) + google-apis-core (>= 0.5, < 2.a) + google-cloud-core (1.6.0) + google-cloud-env (~> 1.0) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.2.0) + google-cloud-storage (1.36.2) + addressable (~> 2.8) + digest-crc (~> 0.4) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.1) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) + mini_mime (~> 1.0) + googleauth (1.1.3) + faraday (>= 0.17.3, < 3.a) + jwt (>= 1.4, < 3.0) + memoist (~> 0.16) + multi_json (~> 1.11) + os (>= 0.9, < 2.0) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) + domain_name (~> 0.5) + httpclient (2.8.3) + jmespath (1.6.1) + json (2.6.2) + jwt (2.4.1) + memoist (0.16.2) + mini_magick (4.11.0) + mini_mime (1.1.2) + multi_json (1.15.0) + multipart-post (2.0.0) + nanaimo (0.3.0) + naturally (2.2.1) + optparse (0.1.1) + os (1.1.4) + plist (3.6.0) + public_suffix (4.0.7) + rake (13.0.6) + representable (3.2.0) + declarative (< 0.1.0) + trailblazer-option (>= 0.1.1, < 0.2.0) + uber (< 0.2.0) + retriable (3.1.2) + rexml (3.2.5) + rouge (2.0.7) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) + security (0.1.3) + signet (0.16.1) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.0) + jwt (>= 1.5, < 3.0) + multi_json (~> 1.10) + simctl (1.6.8) + CFPropertyList + naturally + terminal-notifier (2.0.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.7.0) + word_wrap (1.0.0) + xcodeproj (1.21.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + xcpretty (0.3.0) + rouge (~> 2.0.7) + xcpretty-travis-formatter (1.0.1) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + fastlane + +BUNDLED WITH + 2.1.4 diff --git a/android/app/.gitignore b/android/app/.gitignore new file mode 100644 index 000000000..043df802a --- /dev/null +++ b/android/app/.gitignore @@ -0,0 +1,2 @@ +/build/* +!/build/.npmkeep diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 000000000..06689b63c --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,53 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + defaultConfig { + applicationId "com.twohundredok.organice" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + aaptOptions { + // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. + // Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61 + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~' + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +repositories { + flatDir{ + dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs' + } +} + +dependencies { + implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion" + implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion" + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation project(':capacitor-android') + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation project(':capacitor-cordova-android-plugins') +} + +apply from: 'capacitor.build.gradle' + +try { + def servicesJSON = file('google-services.json') + if (servicesJSON.text) { + apply plugin: 'com.google.gms.google-services' + } +} catch(Exception e) { + logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work") +} diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle new file mode 100644 index 000000000..5f94affb4 --- /dev/null +++ b/android/app/capacitor.build.gradle @@ -0,0 +1,20 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN + +android { + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } +} + +apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" +dependencies { + implementation project(':capacitor-app') + implementation project(':send-intent') + +} + + +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java new file mode 100644 index 000000000..f2c2217ef --- /dev/null +++ b/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import android.content.Context; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.getcapacitor.app", appContext.getPackageName()); + } +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8b95ab90e --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/assets/capacitor.config.json b/android/app/src/main/assets/capacitor.config.json new file mode 100644 index 000000000..b0035720b --- /dev/null +++ b/android/app/src/main/assets/capacitor.config.json @@ -0,0 +1,9 @@ +{ + "appId": "com.twohundredok.organice", + "appName": "organice", + "webDir": "release", + "bundledWebRuntime": false, + "server": { + "cleartext": true + } +} diff --git a/android/app/src/main/assets/capacitor.plugins.json b/android/app/src/main/assets/capacitor.plugins.json new file mode 100644 index 000000000..476076f87 --- /dev/null +++ b/android/app/src/main/assets/capacitor.plugins.json @@ -0,0 +1,10 @@ +[ + { + "pkg": "@capacitor/app", + "classpath": "com.capacitorjs.plugins.app.AppPlugin" + }, + { + "pkg": "send-intent", + "classpath": "de.mindlib.sendIntent.SendIntent" + } +] diff --git a/android/app/src/main/java/com/twohundredok/organice/MainActivity.java b/android/app/src/main/java/com/twohundredok/organice/MainActivity.java new file mode 100644 index 000000000..bacd7e4fd --- /dev/null +++ b/android/app/src/main/java/com/twohundredok/organice/MainActivity.java @@ -0,0 +1,5 @@ +package com.twohundredok.organice; + +import com.getcapacitor.BridgeActivity; + +public class MainActivity extends BridgeActivity {} diff --git a/android/app/src/main/res/drawable-land-hdpi/splash.png b/android/app/src/main/res/drawable-land-hdpi/splash.png new file mode 100644 index 000000000..e31573b4f Binary files /dev/null and b/android/app/src/main/res/drawable-land-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-mdpi/splash.png b/android/app/src/main/res/drawable-land-mdpi/splash.png new file mode 100644 index 000000000..f7a64923e Binary files /dev/null and b/android/app/src/main/res/drawable-land-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-xhdpi/splash.png b/android/app/src/main/res/drawable-land-xhdpi/splash.png new file mode 100644 index 000000000..807725501 Binary files /dev/null and b/android/app/src/main/res/drawable-land-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-xxhdpi/splash.png b/android/app/src/main/res/drawable-land-xxhdpi/splash.png new file mode 100644 index 000000000..14c6c8fe3 Binary files /dev/null and b/android/app/src/main/res/drawable-land-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-land-xxxhdpi/splash.png b/android/app/src/main/res/drawable-land-xxxhdpi/splash.png new file mode 100644 index 000000000..244ca2506 Binary files /dev/null and b/android/app/src/main/res/drawable-land-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-hdpi/splash.png b/android/app/src/main/res/drawable-port-hdpi/splash.png new file mode 100644 index 000000000..74faaa583 Binary files /dev/null and b/android/app/src/main/res/drawable-port-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-mdpi/splash.png b/android/app/src/main/res/drawable-port-mdpi/splash.png new file mode 100644 index 000000000..e944f4ad4 Binary files /dev/null and b/android/app/src/main/res/drawable-port-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-xhdpi/splash.png b/android/app/src/main/res/drawable-port-xhdpi/splash.png new file mode 100644 index 000000000..564a82ff9 Binary files /dev/null and b/android/app/src/main/res/drawable-port-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-xxhdpi/splash.png b/android/app/src/main/res/drawable-port-xxhdpi/splash.png new file mode 100644 index 000000000..bfabe6871 Binary files /dev/null and b/android/app/src/main/res/drawable-port-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-port-xxxhdpi/splash.png b/android/app/src/main/res/drawable-port-xxxhdpi/splash.png new file mode 100644 index 000000000..692907126 Binary files /dev/null and b/android/app/src/main/res/drawable-port-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..c7bd21dbd --- /dev/null +++ b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..d5fccc538 --- /dev/null +++ b/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/drawable/splash.png b/android/app/src/main/res/drawable/splash.png new file mode 100644 index 000000000..f7a64923e Binary files /dev/null and b/android/app/src/main/res/drawable/splash.png differ diff --git a/android/app/src/main/res/layout/activity_main.xml b/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..b5ad13870 --- /dev/null +++ b/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..036d09bc5 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..036d09bc5 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..c023e5059 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..2127973b2 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..b441f37d6 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..72905b854 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..8ed0605c2 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..9502e47a2 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..4d1e07710 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..df0f15880 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..853db043d Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6cdf97c11 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..2960cbb61 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..8e3093a86 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..46de6e255 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..d2ea9abed Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..a40d73e9c Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml new file mode 100644 index 000000000..c5d5899fd --- /dev/null +++ b/android/app/src/main/res/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + \ No newline at end of file diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..b4bc6309c --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + + organice + organice + com.twohundredok.organice + com.twohundredok.organice + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..be874e54a --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/config.xml b/android/app/src/main/res/xml/config.xml new file mode 100644 index 000000000..1b1b0e0dc --- /dev/null +++ b/android/app/src/main/res/xml/config.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/file_paths.xml b/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 000000000..bd0c4d80d --- /dev/null +++ b/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java b/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java new file mode 100644 index 000000000..029732784 --- /dev/null +++ b/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java @@ -0,0 +1,18 @@ +package com.getcapacitor.myapp; + +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 000000000..637f81f06 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.google.gms:google-services:4.3.13' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +apply from: "variables.gradle" + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + + diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle new file mode 100644 index 000000000..7030d8533 --- /dev/null +++ b/android/capacitor.settings.gradle @@ -0,0 +1,9 @@ +// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN +include ':capacitor-android' +project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') + +include ':capacitor-app' +project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android') + +include ':send-intent' +project(':send-intent').projectDir = new File('../node_modules/send-intent/android') diff --git a/android/fastlane/Appfile b/android/fastlane/Appfile new file mode 100644 index 000000000..88f0d6e6e --- /dev/null +++ b/android/fastlane/Appfile @@ -0,0 +1,3 @@ +# -*-ruby-*- +json_key_file("../.ok/play-store-credentials.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one +package_name("com.twohundredok.organice") # e.g. com.krausefx.app diff --git a/android/fastlane/Fastfile b/android/fastlane/Fastfile new file mode 100644 index 000000000..c90510223 --- /dev/null +++ b/android/fastlane/Fastfile @@ -0,0 +1,40 @@ +# -*-ruby-*- + +# This file contains the fastlane.tools configuration +# You can find the documentation at https://docs.fastlane.tools +# +# For a list of all available actions, check out +# +# https://docs.fastlane.tools/actions +# +# For a list of all available plugins, check out +# +# https://docs.fastlane.tools/plugins/available-plugins +# + +# Uncomment the line if you want fastlane to automatically update itself +# update_fastlane + +default_platform(:android) + +platform :android do + desc "Runs all the tests" + lane :test do + gradle(task: "test") + end + + desc "Submit a new Beta Build to Crashlytics Beta" + lane :beta do + gradle(task: "clean assembleRelease") + crashlytics + + # sh "your_script.sh" + # You can also use other beta testing services here + end + + desc "Deploy a new version to the Google Play" + lane :deploy do + gradle(task: "clean assembleRelease") + upload_to_play_store + end +end diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 000000000..0566c221d --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..41d9927a4 Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..92f06b50f --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/android/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/android/gradlew.bat b/android/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 000000000..3b4431d77 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +include ':capacitor-cordova-android-plugins' +project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/') + +apply from: 'capacitor.settings.gradle' \ No newline at end of file diff --git a/android/variables.gradle b/android/variables.gradle new file mode 100644 index 000000000..2dbd75af6 --- /dev/null +++ b/android/variables.gradle @@ -0,0 +1,16 @@ +ext { + minSdkVersion = 22 + compileSdkVersion = 32 + targetSdkVersion = 32 + androidxActivityVersion = '1.4.0' + androidxAppCompatVersion = '1.4.2' + androidxCoordinatorLayoutVersion = '1.2.0' + androidxCoreVersion = '1.8.0' + androidxFragmentVersion = '1.4.1' + junitVersion = '4.13.2' + androidxJunitVersion = '1.1.3' + androidxEspressoCoreVersion = '3.4.0' + cordovaAndroidVersion = '10.1.1' + coreSplashScreenVersion = '1.0.0-rc01' + androidxWebkitVersion = '1.4.0' +} \ No newline at end of file diff --git a/capacitor.config.ts b/capacitor.config.ts new file mode 100644 index 000000000..3c3ad490b --- /dev/null +++ b/capacitor.config.ts @@ -0,0 +1,20 @@ +import { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + appId: 'com.twohundredok.organice', + appName: 'organice', + webDir: 'release', + bundledWebRuntime: false, + server: { + // hostname: 'localhost', // default: localhost + // iosScheme: 'organice', // default: ionic + // androidScheme: 'organice', // default: http + // allowNavigation: ['https://gitlab.com'], + + // To allow http requests to WebDAV server. Not need to force + // users to use https. + cleartext: true + } +}; + +export default config; diff --git a/images/api_32.png b/images/api_32.png new file mode 100644 index 000000000..c20bb89ad Binary files /dev/null and b/images/api_32.png differ diff --git a/package.json b/package.json index 2d51189ed..1b1201dc5 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,14 @@ "version": "0.2.0", "private": true, "engines": { - "node": "^12.13.1" + "node": "^12.20.0" }, "dependencies": { + "@babel/helper-environment-visitor": "^7.18.2", "@bity/oauth2-auth-code-pkce": "^2.13.0", + "@capacitor/android": "^4.0.0", + "@capacitor/app": "^4.0.0", + "@capacitor/core": "^4.0.0", "aos": "^2.3.4", "bowser": "^2.11.0", "classnames": "^2.2.6", @@ -26,17 +30,18 @@ "react-motion": "^0.5.2", "react-redux": "^7.2.1", "react-router-dom": "5.2.0", - "react-scripts": "3.4.3", + "react-scripts": "4.0.3", "redux": "^4.1.0", "redux-thunk": "^2.3.0", "redux-undo": "1.0.1", + "send-intent": "^3.0.11", "webdav": "^3.3.0" }, "scripts": { - "start": "./bin/compile_search_parser.sh && react-scripts start", - "build": "./bin/compile_search_parser.sh && react-scripts build", + "start": "make start", + "build": "make build", "test:dbg": "./bin/compile_search_parser.sh && react-scripts --inspect-brk test --runInBand --no-cache", - "test": "./bin/compile_search_parser.sh && react-scripts test --env=jsdom", + "test": "make test", "coverage": "./bin/compile_search_parser.sh && react-scripts test --env=jsdom --coverage --watchAll=false", "eslint": "./node_modules/.bin/eslint --cache .", "nibble": "./node_modules/.bin/eslint-nibble --cache .", @@ -47,10 +52,11 @@ "postinstall": "if [ \"$ON_HEROKU\" ]; then npm install -g serve; fi" }, "devDependencies": { + "@capacitor/cli": "^4.0.0", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "12.0.0", "babel-eslint": "^10.1.0", - "eslint": "^6.6.0", + "eslint": "^7.32.0", "eslint-nibble": "^6.1.0", "eslint-plugin-jest": "^23.20.0", "eslint-plugin-react": "^7.23.2", diff --git a/src/App.js b/src/App.js index abf9b65b6..4bd5035bf 100644 --- a/src/App.js +++ b/src/App.js @@ -40,22 +40,47 @@ import { import _ from 'lodash'; import { Map } from 'immutable'; +import AppUrlListener from './AppUrlListener'; + import { configure } from 'react-hotkeys'; + +import { SendIntent } from 'send-intent'; + // do handle hotkeys even if they come from within 'input', 'select' or 'textarea' configure({ ignoreTags: [] }); +SendIntent.checkSendIntentReceived() + .then((result) => { + if (result) { + console.log('SendIntent received'); + console.log(JSON.stringify(result)); + } + if (result.url) { + let resultUrl = decodeURIComponent(result.url); + console.log(resultUrl); + // Filesystem.readFile({path: resultUrl}) + // .then((content) => { + // console.log(content.data); + // }) + // .catch((err) => console.error(err)); + } + }) + .catch((err) => console.error(err)); + const handleGitLabAuthResponse = async (oauthClient) => { let success = false; + let error; try { success = await oauthClient.isReturningFromAuthServer(); await oauthClient.getAccessToken(); - } catch { + } catch (e) { + error = e; success = false; } if (!success) { // Edge case: somehow OAuth success redirect occurred but there isn't a code in // the current location's search params. This /shouldn't/ happen in practice. - alert('Unexpected sign in error, please try again'); + alert('Unexpected sign in error, please try again: ' + error); return; } @@ -68,67 +93,72 @@ const handleGitLabAuthResponse = async (oauthClient) => { } }; -export default class App extends PureComponent { - constructor(props) { - super(props); - - runAllMigrations(); - - const initialState = readInitialState(); - - const hashContents = parseQueryString(window.location.hash); - const authenticatedSyncService = getPersistedField('authenticatedSyncService', true); - let client = null; - - if (!!authenticatedSyncService) { - switch (authenticatedSyncService) { - case 'Dropbox': - const dropboxAccessToken = hashContents.access_token; - if (dropboxAccessToken) { - client = createDropboxSyncBackendClient(dropboxAccessToken); - initialState.syncBackend = Map({ - isAuthenticated: true, - client, - }); - persistField('dropboxAccessToken', dropboxAccessToken); - window.location.hash = ''; - } else { - const persistedDropboxAccessToken = getPersistedField('dropboxAccessToken', true); - if (!!persistedDropboxAccessToken) { - client = createDropboxSyncBackendClient(persistedDropboxAccessToken); - initialState.syncBackend = Map({ - isAuthenticated: true, - client, - }); - } - } - break; - case 'GitLab': - const gitlabOAuth = createGitlabOAuth(); - if (gitlabOAuth.isAuthorized()) { - client = createGitLabSyncBackendClient(gitlabOAuth); +export function handleAuthenticatedSyncService(initialState) { + const hashContents = parseQueryString(window.location.hash); + const authenticatedSyncService = getPersistedField('authenticatedSyncService', true); + let client = null; + + if (!!authenticatedSyncService) { + switch (authenticatedSyncService) { + case 'Dropbox': + const dropboxAccessToken = hashContents.access_token; + if (dropboxAccessToken) { + client = createDropboxSyncBackendClient(dropboxAccessToken); + initialState.syncBackend = Map({ + isAuthenticated: true, + client, + }); + persistField('dropboxAccessToken', dropboxAccessToken); + window.location.hash = ''; + } else { + const persistedDropboxAccessToken = getPersistedField('dropboxAccessToken', true); + if (!!persistedDropboxAccessToken) { + client = createDropboxSyncBackendClient(persistedDropboxAccessToken); initialState.syncBackend = Map({ isAuthenticated: true, client, }); - } else { - handleGitLabAuthResponse(gitlabOAuth); } - break; - case 'WebDAV': - client = createWebDAVSyncBackendClient( - getPersistedField('webdavEndpoint'), - getPersistedField('webdavUsername'), - getPersistedField('webdavPassword') - ); + } + break; + case 'GitLab': + const gitlabOAuth = createGitlabOAuth(); + if (gitlabOAuth.isAuthorized()) { + client = createGitLabSyncBackendClient(gitlabOAuth); initialState.syncBackend = Map({ isAuthenticated: true, client, }); - break; - default: - } + } else { + handleGitLabAuthResponse(gitlabOAuth); + } + break; + case 'WebDAV': + client = createWebDAVSyncBackendClient( + getPersistedField('webdavEndpoint'), + getPersistedField('webdavUsername'), + getPersistedField('webdavPassword') + ); + initialState.syncBackend = Map({ + isAuthenticated: true, + client, + }); + break; + default: } + } + return client; +} + +export default class App extends PureComponent { + constructor(props) { + super(props); + + runAllMigrations(); + + const initialState = readInitialState(); + + const client = handleAuthenticatedSyncService(initialState); const queryStringContents = parseQueryString(window.location.search); const { captureFile, captureTemplateName, captureContent } = queryStringContents; @@ -209,6 +239,7 @@ export default class App extends PureComponent { return ( + diff --git a/src/AppUrlListener.js b/src/AppUrlListener.js new file mode 100644 index 000000000..7487c6af4 --- /dev/null +++ b/src/AppUrlListener.js @@ -0,0 +1,46 @@ +import { useEffect } from 'react'; +// import { useHistory } from 'react-router-dom'; +import { App } from '@capacitor/app'; +import { handleAuthenticatedSyncService } from './App'; +import { readInitialState } from './util/settings_persister'; + +const AppUrlListener = () => { + // let history = useHistory(); + useEffect(() => { + App.addListener('appUrlOpen', (event) => { + // Some OAuth providers (i.e. GitLab) use query parameters. + // Migrate them from the event.url to the actual + // window.location. + const newUrl = new URL(window.location.href); + for (const entry of new URL(event.url).searchParams.entries()) { + newUrl.searchParams.set(entry[0], entry[1]); + } + // Some OAuth providers (i.e. Dropbox) use the hash. Migrate it + // from the event.url to window.location. + newUrl.hash = new URL(event.url).hash; + window.history.pushState(null, '', newUrl); + handleAuthenticatedSyncService(readInitialState()); + + // HACK: After the above code, the Dropbox login has succeeded. + // However, the constructor in App.js has to run. For some + // reason, this implicitly happens for GitLab. This could most + // definitively be implemented in a more readable manner by + // refactoring the App.js constructor. + if (newUrl.hash) window.location.reload(); + + // // Example url: https://beerswift.app/tabs/tab2 + // // slug = /tabs/tab2 + // const slug = event.url.split('organice.200ok.ch').pop(); + // if (slug) { + // //alert(slug); + // history.push(slug); + // } + // // If no match, do nothing - let regular routing + // // logic take over + }); + }, []); + + return null; +}; + +export default AppUrlListener; diff --git a/src/components/OrgFile/OrgFile.integration.test.js b/src/components/OrgFile/OrgFile.integration.test.js index 19047b24b..f3bd449f9 100644 --- a/src/components/OrgFile/OrgFile.integration.test.js +++ b/src/components/OrgFile/OrgFile.integration.test.js @@ -26,7 +26,7 @@ import { STATIC_FILE_PREFIX } from '../../lib/org_utils'; afterEach(cleanup); describe('Render all views', () => { - jest.mock('react-hotkeys', () => { + jest.doMock('react-hotkeys', () => { const React = require('react'); const Fragment = React.Fragment; diff --git a/src/components/SyncServiceSignIn/index.js b/src/components/SyncServiceSignIn/index.js index 4708aa709..fa32a6520 100644 --- a/src/components/SyncServiceSignIn/index.js +++ b/src/components/SyncServiceSignIn/index.js @@ -1,5 +1,3 @@ -/* global process */ - import React, { PureComponent, useState } from 'react'; import './stylesheet.css'; @@ -16,6 +14,8 @@ import { import { Dropbox } from 'dropbox'; import _ from 'lodash'; +import { redirectUrl } from '../../util/redirect_url'; + function WebDAVForm() { const [isVisible, setIsVisible] = useState(false); const toggleVisible = () => setIsVisible(!isVisible); @@ -163,7 +163,7 @@ export default class SyncServiceSignIn extends PureComponent { clientId: process.env.REACT_APP_DROPBOX_CLIENT_ID, fetch: fetch.bind(window), }); - dropbox.auth.getAuthenticationUrl(window.location.origin + '/').then((authURL) => { + dropbox.auth.getAuthenticationUrl(redirectUrl()).then((authURL) => { window.location = authURL; }); } @@ -190,16 +190,21 @@ export default class SyncServiceSignIn extends PureComponent { -