diff --git a/.github/workflows/manual-release-core.yml b/.github/workflows/manual-release-core.yml
new file mode 100644
index 00000000..02569e98
--- /dev/null
+++ b/.github/workflows/manual-release-core.yml
@@ -0,0 +1,44 @@
+name: Manual release workflow
+
+on:
+ workflow_dispatch:
+
+jobs:
+ # This workflow contains a single job called "build"
+ build:
+ # The type of runner that the job will run on
+ runs-on: ubuntu-latest
+
+ # Steps represent a sequence of tasks that will be executed as part of the job
+ steps:
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
+ - name: Check out code
+ uses: actions/checkout@v2
+
+ - name:
+ run: |
+ echo "${{secrets.SECRING_GPG_B64}}" > ~/.gradle/secring.gpg.b64
+ base64 -d ~/.gradle/secring.gpg.b64 > ~/.gradle/secring.gpg
+ touch ~/.gradle/gradle.properties
+ echo "signing.keyId=${{secrets.SIGNING_KEYID}}" >> ~/.gradle/gradle.properties
+ echo "signing.password=${{secrets.SIGNING_PASSWORD}}" >> ~/.gradle/gradle.properties
+ echo "signing.secretKeyRingFile=~/.gradle/secring.gpg" >> ~/.gradle/gradle.properties
+ echo "mavenCentralRepositoryUsername=${{secrets.MAVEN_CENTRAL_REPOSITORY_USERNAME}}" >> ~/.gradle/gradle.properties
+ echo "mavenCentralRepositoryPassword=${{secrets.MAVEN_CENTRAL_REPOSITORY_PASSWORD}}" >> ~/.gradle/gradle.properties
+
+ - name: Check out java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+
+ - name: Run Detekt
+ run: ./gradlew :toggles-core:detekt
+
+ - name: Run Android Lint
+ run: ./gradlew :toggles-core:lint
+
+ - name: Run Android Unit test
+ run: ./gradlew :toggles-core:testDebugUnitTest
+
+ - name: Publish core library
+ run: ./gradlew :toggles-core:publish --no-daemon --no-parallel
diff --git a/.github/workflows/manual-release-flow.yml b/.github/workflows/manual-release-flow.yml
new file mode 100644
index 00000000..4014130f
--- /dev/null
+++ b/.github/workflows/manual-release-flow.yml
@@ -0,0 +1,44 @@
+name: Manual release workflow
+
+on:
+ workflow_dispatch:
+
+jobs:
+ # This workflow contains a single job called "build"
+ build:
+ # The type of runner that the job will run on
+ runs-on: ubuntu-latest
+
+ # Steps represent a sequence of tasks that will be executed as part of the job
+ steps:
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
+ - name: Check out code
+ uses: actions/checkout@v2
+
+ - name:
+ run: |
+ echo "${{secrets.SECRING_GPG_B64}}" > ~/.gradle/secring.gpg.b64
+ base64 -d ~/.gradle/secring.gpg.b64 > ~/.gradle/secring.gpg
+ touch ~/.gradle/gradle.properties
+ echo "signing.keyId=${{secrets.SIGNING_KEYID}}" >> ~/.gradle/gradle.properties
+ echo "signing.password=${{secrets.SIGNING_PASSWORD}}" >> ~/.gradle/gradle.properties
+ echo "signing.secretKeyRingFile=~/.gradle/secring.gpg" >> ~/.gradle/gradle.properties
+ echo "mavenCentralRepositoryUsername=${{secrets.MAVEN_CENTRAL_REPOSITORY_USERNAME}}" >> ~/.gradle/gradle.properties
+ echo "mavenCentralRepositoryPassword=${{secrets.MAVEN_CENTRAL_REPOSITORY_PASSWORD}}" >> ~/.gradle/gradle.properties
+
+ - name: Check out java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+
+ - name: Run Detekt
+ run: ./gradlew :toggles-flow:detekt
+
+ - name: Run Android Lint
+ run: ./gradlew :toggles-flow:lint
+
+ - name: Run Android Unit test
+ run: ./gradlew :toggles-flow:testDebugUnitTest
+
+ - name: Publish flow library
+ run: ./gradlew :toggles-flow:publish --no-daemon --no-parallel
diff --git a/.github/workflows/manual-release-prefs.yml b/.github/workflows/manual-release-prefs.yml
new file mode 100644
index 00000000..22e42d54
--- /dev/null
+++ b/.github/workflows/manual-release-prefs.yml
@@ -0,0 +1,44 @@
+name: Manual release workflow
+
+on:
+ workflow_dispatch:
+
+jobs:
+ # This workflow contains a single job called "build"
+ build:
+ # The type of runner that the job will run on
+ runs-on: ubuntu-latest
+
+ # Steps represent a sequence of tasks that will be executed as part of the job
+ steps:
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
+ - name: Check out code
+ uses: actions/checkout@v2
+
+ - name:
+ run: |
+ echo "${{secrets.SECRING_GPG_B64}}" > ~/.gradle/secring.gpg.b64
+ base64 -d ~/.gradle/secring.gpg.b64 > ~/.gradle/secring.gpg
+ touch ~/.gradle/gradle.properties
+ echo "signing.keyId=${{secrets.SIGNING_KEYID}}" >> ~/.gradle/gradle.properties
+ echo "signing.password=${{secrets.SIGNING_PASSWORD}}" >> ~/.gradle/gradle.properties
+ echo "signing.secretKeyRingFile=~/.gradle/secring.gpg" >> ~/.gradle/gradle.properties
+ echo "mavenCentralRepositoryUsername=${{secrets.MAVEN_CENTRAL_REPOSITORY_USERNAME}}" >> ~/.gradle/gradle.properties
+ echo "mavenCentralRepositoryPassword=${{secrets.MAVEN_CENTRAL_REPOSITORY_PASSWORD}}" >> ~/.gradle/gradle.properties
+
+ - name: Check out java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+
+ - name: Run Detekt
+ run: ./gradlew :toggles-prefs:detekt
+
+ - name: Run Android Lint
+ run: ./gradlew :toggles-prefs:lint
+
+ - name: Run Android Unit test
+ run: ./gradlew :toggles-prefs:testDebugUnitTest
+
+ - name: Publish core library
+ run: ./gradlew :toggles-prefs:publish --no-daemon --no-parallel
diff --git a/.github/workflows/manual-release.yml b/.github/workflows/manual-release.yml
index 24b071f2..146b9ccf 100644
--- a/.github/workflows/manual-release.yml
+++ b/.github/workflows/manual-release.yml
@@ -29,7 +29,7 @@ jobs:
- name: Check out java
uses: actions/setup-java@v1
with:
- java-version: 1.8
+ java-version: 11
- name: Run Detekt
run: ./gradlew detekt
diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml
index 69cfedc3..d7ac2801 100644
--- a/.github/workflows/post-merge.yml
+++ b/.github/workflows/post-merge.yml
@@ -19,7 +19,7 @@ jobs:
- name: Check out java
uses: actions/setup-java@v1
with:
- java-version: 1.8
+ java-version: 11
- name: Build apks
run: ./gradlew :toggles-app:packageDebug :toggles-sample:packageDebug
@@ -29,3 +29,4 @@ jobs:
with:
name: Apks
path: '**/build/outputs/apk/*'
+ retention-days: 14
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 878ff05f..18383c1d 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -19,7 +19,7 @@ jobs:
- name: Check out java
uses: actions/setup-java@v1
with:
- java-version: 1.8
+ java-version: 11
- name: Run Detekt
run: ./gradlew detekt
@@ -35,4 +35,5 @@ jobs:
if: failure()
with:
name: Reports
- path: '**/build/reports/*'
\ No newline at end of file
+ path: '**/build/reports/*'
+ retention-days: 2
diff --git a/README.md b/README.md
index 586ac161..118a3c93 100644
--- a/README.md
+++ b/README.md
@@ -13,10 +13,10 @@ Stores settings / toggles behind a content provider.
This is a development tools meant to facilitate feature switching in an external app so that configurations will be retained across clear data / uninstalls.
-2 premade libraries to talk to the toggles application. "Prefs" and "Coroutines":
+2 premade libraries to talk to the toggles application. "Prefs" and "Flow":
-## Toggles-coroutines library
-Exposes switches from toggles using a kotlin stream.
+## Toggles-flow library
+Exposes switches from toggles using a kotlin flow.
## Toggles-prefs library
One-shot fetch of a toggle. Similar API as androids SharedPreferences.
diff --git a/build.gradle.kts b/build.gradle.kts
index 296058b9..27742a9b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,6 +2,9 @@ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
+
+ val composeVersion by extra("1.0.0-beta02")
+
repositories {
google()
mavenCentral()
@@ -10,29 +13,33 @@ buildscript {
}
dependencies {
- classpath("com.android.tools:r8:2.1.75")
- classpath("com.android.tools.build:gradle:4.1.1")
- classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21")
- classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.3.2")
+ classpath("com.android.tools.build:gradle:7.0.0-alpha10")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.31")
+ classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.3.4")
classpath("com.google.gms:oss-licenses:0.9.2")
- classpath("com.google.dagger:hilt-android-gradle-plugin:2.30.1-alpha")
- // https://github.com/Triple-T/gradle-play-publisher/issues/864
- classpath("com.github.triplet.gradle:play-publisher:3.0.0")
- classpath("com.google.gms:google-services:4.3.4")
+ classpath("com.google.dagger:hilt-android-gradle-plugin:2.33-beta")
+ classpath("com.google.gms:google-services:4.3.5")
+ classpath("com.vanniktech:gradle-maven-publish-plugin:0.14.2")
+ classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.4.30")
}
}
-dependencies {
- detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
-}
-
plugins {
- id("com.github.ben-manes.versions") version "0.36.0"
+ id("com.github.ben-manes.versions") version "0.38.0"
id("se.eelde.build-optimizations") version "0.2.0"
- id("io.gitlab.arturbosch.detekt") version "1.14.2"
+ id("io.gitlab.arturbosch.detekt") version "1.16.0"
}
allprojects {
+ apply(plugin = "io.gitlab.arturbosch.detekt")
+
+ dependencies {
+ detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.16.0")
+ }
+ detekt {
+ autoCorrect = true
+ }
+
repositories {
google()
mavenCentral()
diff --git a/gradle.properties b/gradle.properties
index 4c054e00..8ef65895 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,15 +6,15 @@
# 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=-Xmx2g
+org.gradle.jvmargs=-Xmx2g -Xms500m -Dfile.encoding=UTF-8
+
# 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
-VERSION_NAME=0.3
-VERSION_CODE=5
GROUP=se.eelde.toggles
POM_DESCRIPTION=Toggles
+POM_INCEPTION_YEAR=2018
POM_URL=https://github.com/erikeelde/toggles
POM_SCM_URL=https://github.com/erikeelde/toggles
POM_SCM_CONNECTION=scm:git@github.com:erikeelde/toggles.git
@@ -24,6 +24,9 @@ POM_LICENCE_URL=https://raw.githubusercontent.com/erikeelde/toggles/master/LICEN
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=erikeelde, warting
POM_DEVELOPER_NAME=Erik Eelde, Stefan Wärting
+
+RELEASE_REPOSITORY_URL=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
+SNAPSHOT_REPOSITORY_URL=https://s01.oss.sonatype.org/content/repositories/snapshots/
# Enable rudimentary R class namespacing where each library only contains
# references to the resources it declares instead of declarations plus all
# transitive dependency references.
@@ -31,3 +34,10 @@ POM_DEVELOPER_NAME=Erik Eelde, Stefan Wärting
android.nonTransitiveRClass=false
android.useAndroidX=true
android.enableJetifier=false
+
+#kotlin.caching.enabled=true # default false
+#kotlin.incremental.usePreciseJavaTracking=true #default false
+#kapt.use.worker.api=true
+#kapt.include.compile.classpath=false
+#kapt.incremental.apt=true
+#kotlin.parallel.tasks.in.project=true
diff --git a/gradle/gradle-mvn-push.gradle b/gradle/gradle-mvn-push.gradle
deleted file mode 100644
index 58aaa11b..00000000
--- a/gradle/gradle-mvn-push.gradle
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2013 Chris Banes
- *
- * 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
- *
- * http://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.
- */
-
-apply plugin: 'maven'
-apply plugin: 'signing'
-
-def isReleaseBuild() {
- return VERSION_NAME.contains("SNAPSHOT") == false
-}
-
-def getReleaseRepositoryUrl() {
- return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
- : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
-}
-
-def getSnapshotRepositoryUrl() {
- return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
- : "https://oss.sonatype.org/content/repositories/snapshots/"
-}
-
-def getRepositoryUsername() {
- return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
-}
-
-def getRepositoryPassword() {
- return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
-}
-
-afterEvaluate { project ->
- uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
-
- pom.groupId = GROUP
- pom.artifactId = POM_ARTIFACT_ID
- pom.version = VERSION_NAME
-
- repository(url: getReleaseRepositoryUrl()) {
- authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
- }
- snapshotRepository(url: getSnapshotRepositoryUrl()) {
- authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
- }
-
- pom.project {
- name POM_NAME
- packaging POM_PACKAGING
- description POM_DESCRIPTION
- url POM_URL
-
- scm {
- url POM_SCM_URL
- connection POM_SCM_CONNECTION
- developerConnection POM_SCM_DEV_CONNECTION
- }
-
- licenses {
- license {
- name POM_LICENCE_NAME
- url POM_LICENCE_URL
- distribution POM_LICENCE_DIST
- }
- }
-
- developers {
- developer {
- id POM_DEVELOPER_ID
- name POM_DEVELOPER_NAME
- }
- }
- }
- }
- }
- }
-
- signing {
- required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
- sign configurations.archives
- }
-
- task androidJavadocs(type: Javadoc) {
- source = android.sourceSets.main.java.srcDirs
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
- failOnError false
- }
-
- task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
- classifier = 'javadoc'
- from androidJavadocs.destinationDir
- }
-
- task androidSourcesJar(type: Jar) {
- classifier = 'sources'
- from android.sourceSets.main.java.sourceFiles
- }
-
- artifacts {
- archives androidSourcesJar
- archives androidJavadocsJar
- }
-}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5fbf4944..78549f88 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-all.zip
+distributionUrl=https://services.gradle.org/distributions/gradle-6.8.3-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32..ac1b06f9 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,89 +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
+@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/lint.xml b/lint.xml
index a9fd4310..8fedf799 100644
--- a/lint.xml
+++ b/lint.xml
@@ -3,6 +3,8 @@
+
+
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 9fd5ac45..43113e23 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,7 +1,9 @@
+rootProject.name = "Toggles"
+
include(
":toggles-app",
":toggles-core",
- "toggles-coroutines",
+ ":toggles-flow",
":toggles-prefs",
":toggles-sample"
)
diff --git a/toggles-app/build.gradle.kts b/toggles-app/build.gradle.kts
index 61095587..a41ea17f 100644
--- a/toggles-app/build.gradle.kts
+++ b/toggles-app/build.gradle.kts
@@ -10,19 +10,10 @@ plugins {
id("androidx.navigation.safeargs.kotlin")
id("com.google.gms.oss.licenses.plugin")
id("dagger.hilt.android.plugin")
- id("io.gitlab.arturbosch.detekt")
- id("com.github.triplet.play")
+ id("com.github.triplet.play") version "3.3.0-agp4.2"
id("kotlin-android")
}
-dependencies {
- detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
-}
-
-detekt {
- autoCorrect = true
-}
-
kapt {
javacOptions {
// Increase the max count of errors from annotation processors.
@@ -31,10 +22,6 @@ kapt {
}
}
-hilt {
- enableTransformForLocalTests = true
-}
-
play {
serviceAccountCredentials.set(file("../service_account.json"))
defaultToAppBundles.set(true)
@@ -60,6 +47,12 @@ android {
buildFeatures {
viewBinding = true
+ compose = true
+ }
+
+ composeOptions {
+ val composeVersion: String by rootProject.extra
+ kotlinCompilerExtensionVersion = composeVersion
}
testOptions {
@@ -70,10 +63,10 @@ android {
defaultConfig {
applicationId = "se.eelde.toggles"
- minSdk = 16
+ minSdk = 21
targetSdk = 30
- versionCode = 4
- versionName = "1.01.00"
+ versionCode = 5
+ versionName = "1.01.01"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -96,6 +89,10 @@ android {
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
+ freeCompilerArgs = listOfNotNull(
+ "-Xopt-in=kotlin.RequiresOptIn"
+ )
+ useIR = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -110,12 +107,11 @@ android {
getByName("debug") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"))
-
versionNameSuffix = " debug"
// applicationIdSuffix = ".debug"
}
}
- lintOptions {
+ lint {
baselineFile = file("lint-baseline.xml")
isCheckReleaseBuilds = true
isAbortOnError = true
@@ -138,62 +134,80 @@ kapt {
}
dependencies {
+ implementation(project(":toggles-flow"))
+ val composeVersion: String by rootProject.extra
+
+ implementation("androidx.ui:ui-tooling:1.0.0-alpha07")
+ implementation("androidx.compose.runtime:runtime:$composeVersion")
+ implementation("androidx.compose.ui:ui:$composeVersion")
+ implementation("androidx.compose.foundation:foundation-layout:$composeVersion")
+ implementation("androidx.compose.material:material:$composeVersion")
+ implementation("androidx.compose.material:material-icons-extended:$composeVersion")
+ implementation("androidx.compose.foundation:foundation:$composeVersion")
+ implementation("androidx.compose.animation:animation:$composeVersion")
+ implementation("androidx.compose.ui:ui-tooling:$composeVersion")
+ implementation("androidx.compose.runtime:runtime-livedata:$composeVersion")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha03")
+ implementation("androidx.navigation:navigation-compose:1.0.0-alpha09")
+
implementation("androidx.legacy:legacy-support-v4:1.0.0")
- testImplementation("junit:junit:4.13.1")
+ testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test:core-ktx:1.3.0")
testImplementation("androidx.test.ext:truth:1.3.0")
testImplementation("androidx.test:rules:1.3.0")
testImplementation("androidx.test:runner:1.3.0")
testImplementation("androidx.test.ext:junit:1.1.2")
- testImplementation("androidx.room:room-testing:2.3.0-alpha04")
- testImplementation("org.robolectric:robolectric:4.4")
+ testImplementation("androidx.room:room-testing:2.3.0-beta03")
+ testImplementation("org.robolectric:robolectric:4.5.1")
testImplementation("androidx.test.espresso:espresso-core:3.3.0")
testImplementation("androidx.arch.core:core-testing:2.1.0")
- testImplementation("androidx.work:work-testing:2.4.0")
+ testImplementation("androidx.work:work-testing:2.5.0")
- implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-rc01")
- implementation(platform("com.google.firebase:firebase-bom:26.1.1"))
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0")
+ implementation(platform("com.google.firebase:firebase-bom:26.7.0"))
- implementation("com.google.dagger:hilt-android:2.30.1-alpha")
- kapt("com.google.dagger:hilt-android-compiler:2.30.1-alpha")
- implementation("androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02")
- kapt("androidx.hilt:hilt-compiler:1.0.0-alpha02")
- implementation("androidx.hilt:hilt-work:1.0.0-alpha02")
+ implementation("com.google.dagger:hilt-android:2.33-beta")
+ kapt("com.google.dagger:hilt-android-compiler:2.33-beta")
+ implementation("androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03")
+ kapt("androidx.hilt:hilt-compiler:1.0.0-beta01")
+ implementation("androidx.hilt:hilt-work:1.0.0-beta01")
- testImplementation("com.google.dagger:hilt-android-testing:2.30.1-alpha")
- kaptTest("com.google.dagger:hilt-android-compiler:2.30.1-alpha")
+ testImplementation("com.google.dagger:hilt-android-testing:2.33-beta")
+ kaptTest("com.google.dagger:hilt-android-compiler:2.33-beta")
- implementation("androidx.lifecycle:lifecycle-common-java8:2.3.0-rc01")
- kapt("androidx.room:room-compiler:2.3.0-alpha04")
+ implementation("androidx.lifecycle:lifecycle-common-java8:2.3.0")
+ kapt("androidx.room:room-compiler:2.3.0-beta03")
- implementation("com.google.dagger:dagger:2.30.1")
- kapt("com.google.dagger:dagger-compiler:2.30.1")
+ implementation("com.google.dagger:dagger:2.33")
+ kapt("com.google.dagger:dagger-compiler:2.33")
- implementation("androidx.appcompat:appcompat:1.3.0-alpha02")
- implementation("androidx.recyclerview:recyclerview:1.2.0-beta01")
- implementation("com.google.android.material:material:1.3.0-beta01")
+ implementation("androidx.appcompat:appcompat:1.3.0-beta01")
+ implementation("androidx.recyclerview:recyclerview:1.2.0-beta02")
+ implementation("com.google.android.material:material:1.3.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
implementation("androidx.cardview:cardview:1.0.0")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
- implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-rc01")
- implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-rc01")
- implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:2.3.0-rc01")
- implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-rc01")
- implementation("androidx.room:room-runtime:2.3.0-alpha04")
- implementation("androidx.room:room-ktx:2.3.0-alpha04")
- implementation("androidx.paging:paging-runtime-ktx:3.0.0-alpha11")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0")
+ implementation("androidx.lifecycle:lifecycle-livedata-core-ktx:2.3.0")
+ implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.0")
+ implementation("androidx.room:room-runtime:2.3.0-beta03")
+ implementation("androidx.room:room-ktx:2.3.0-beta03")
+ implementation("androidx.paging:paging-runtime-ktx:3.0.0-beta02")
- implementation("androidx.navigation:navigation-fragment-ktx:2.3.2")
- implementation("androidx.navigation:navigation-ui-ktx:2.3.2")
+ implementation("androidx.navigation:navigation-fragment-ktx:2.3.4")
+ implementation("androidx.navigation:navigation-ui-ktx:2.3.4")
implementation("com.izettle.wrench:wrench-core:0.3")
implementation(project(":toggles-core"))
implementation(project(":toggles-prefs"))
+ implementation(project(":toggles-flow"))
+
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3")
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21")
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2")
+ implementation("androidx.core:core-ktx:1.3.2")
+ implementation("androidx.work:work-runtime-ktx:2.5.0")
- implementation("androidx.core:core-ktx:1.5.0-alpha05")
- implementation("androidx.work:work-runtime-ktx:2.4.0")
+ debugImplementation("com.squareup.leakcanary:leakcanary-android:2.6")
}
diff --git a/toggles-app/lint-baseline.xml b/toggles-app/lint-baseline.xml
index 5b2ec11c..fde2bd79 100644
--- a/toggles-app/lint-baseline.xml
+++ b/toggles-app/lint-baseline.xml
@@ -1,4 +1,3 @@
-
-
+
diff --git a/toggles-app/src/main/AndroidManifest.xml b/toggles-app/src/main/AndroidManifest.xml
index dd42a4b7..dbe79f4b 100644
--- a/toggles-app/src/main/AndroidManifest.xml
+++ b/toggles-app/src/main/AndroidManifest.xml
@@ -36,7 +36,8 @@
android:allowEmbedded="true"
android:documentLaunchMode="always"
android:resizeableActivity="true"
- tools:targetApi="n" >
+ tools:targetApi="n"
+ android:exported="true">
@@ -47,7 +48,8 @@
-
+
diff --git a/toggles-app/src/main/java/com/izettle/wrench/MainActivity.kt b/toggles-app/src/main/java/com/izettle/wrench/MainActivity.kt
index ed95bda5..a6bcaa0d 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/MainActivity.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/MainActivity.kt
@@ -2,11 +2,14 @@ package com.izettle.wrench
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI
import androidx.navigation.ui.setupActionBarWithNavController
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import se.eelde.toggles.R
import se.eelde.toggles.databinding.ActivityMainBinding
import se.eelde.toggles.notification.NotificationWorker
@@ -23,14 +26,18 @@ class MainActivity : AppCompatActivity() {
setContentView(binding.root)
// navController = findNavController(R.id.nav_host_fragment) // https://issuetracker.google.com/issues/142847973
- navController = (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
+ navController =
+ (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment).navController
setupActionBarWithNavController(navController, binding.drawerLayout)
NavigationUI.setupWithNavController(binding.navView, navController)
- NotificationWorker.scheduleNotification(this)
+ lifecycleScope.launch(Dispatchers.IO) {
+ NotificationWorker.scheduleNotification(applicationContext)
+ }
}
- override fun onSupportNavigateUp(): Boolean = NavigationUI.navigateUp(navController, binding.drawerLayout)
+ override fun onSupportNavigateUp(): Boolean =
+ NavigationUI.navigateUp(navController, binding.drawerLayout)
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewHolder.kt b/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewHolder.kt
index 502e17f5..316d4f10 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewHolder.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewHolder.kt
@@ -29,7 +29,8 @@ internal class ApplicationViewHolder(val binding: ApplicationListItemBinding) :
val applicationId = application.id
Navigation.findNavController(v).navigate(
ApplicationsFragmentDirections.actionApplicationsFragmentToConfigurationsFragment(
- applicationId
+ applicationId,
+ application.applicationLabel
)
)
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewModel.kt
index 33378ff6..ac2d1be9 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationViewModel.kt
@@ -1,6 +1,5 @@
package com.izettle.wrench.applicationlist
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
@@ -9,10 +8,12 @@ import androidx.paging.PagingData
import androidx.paging.cachedIn
import com.izettle.wrench.database.WrenchApplication
import com.izettle.wrench.database.WrenchApplicationDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
+import javax.inject.Inject
-internal class ApplicationViewModel
-@ViewModelInject constructor(applicationDao: WrenchApplicationDao) : ViewModel() {
+@HiltViewModel
+internal class ApplicationViewModel @Inject constructor(applicationDao: WrenchApplicationDao) : ViewModel() {
internal val applications: Flow> = Pager(PagingConfig(pageSize = 20)) {
applicationDao.getApplications()
diff --git a/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationsFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationsFragment.kt
index f8eb2f92..ef04fe9f 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationsFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/applicationlist/ApplicationsFragment.kt
@@ -13,11 +13,13 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.launch
import se.eelde.toggles.databinding.FragmentApplicationsBinding
+import se.eelde.toggles.viewLifecycle
@AndroidEntryPoint
internal class ApplicationsFragment : Fragment() {
- private lateinit var binding: FragmentApplicationsBinding
+ private var binding: FragmentApplicationsBinding by viewLifecycle()
+
private val model by viewModels()
override fun onCreateView(
diff --git a/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationViewModel.kt
index 304f41fc..2a24f26a 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationViewModel.kt
@@ -1,7 +1,6 @@
package com.izettle.wrench.configurationlist
import android.text.TextUtils
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
@@ -14,9 +13,12 @@ import com.izettle.wrench.database.WrenchConfigurationDao
import com.izettle.wrench.database.WrenchConfigurationWithValues
import com.izettle.wrench.database.WrenchScope
import com.izettle.wrench.database.WrenchScopeDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
+import javax.inject.Inject
-class ConfigurationViewModel @ViewModelInject internal constructor(
+@HiltViewModel
+class ConfigurationViewModel @Inject internal constructor(
private val applicationDao: WrenchApplicationDao,
configurationDao: WrenchConfigurationDao,
private val scopeDao: WrenchScopeDao
diff --git a/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationsFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationsFragment.kt
index b083e821..b1f3eb90 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationsFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/configurationlist/ConfigurationsFragment.kt
@@ -1,5 +1,6 @@
package com.izettle.wrench.configurationlist
+import android.annotation.SuppressLint
import android.app.ActivityManager
import android.content.Context
import android.content.Intent
@@ -18,25 +19,33 @@ import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
-import com.izettle.wrench.core.Bolt
import com.izettle.wrench.database.WrenchApplication
import com.izettle.wrench.database.WrenchConfigurationWithValues
import com.izettle.wrench.dialogs.scope.ScopeFragment
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
import se.eelde.toggles.R
+import se.eelde.toggles.core.Toggle
+import se.eelde.toggles.flow.toggleFlow
import se.eelde.toggles.databinding.FragmentConfigurationsBinding
+import se.eelde.toggles.viewLifecycle
@AndroidEntryPoint
class ConfigurationsFragment :
Fragment(),
SearchView.OnQueryTextListener,
ConfigurationRecyclerViewAdapter.Listener {
- private lateinit var binding: FragmentConfigurationsBinding
+ private var binding: FragmentConfigurationsBinding by viewLifecycle()
+
private var currentFilter: CharSequence? = null
private var searchView: SearchView? = null
@@ -77,6 +86,7 @@ class ConfigurationsFragment :
FragmentConfigurationsBinding.inflate(layoutInflater, container, false)
.also { binding = it }.root
+ @SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -241,6 +251,8 @@ class ConfigurationsFragment :
}
}
+ @Suppress("LongMethod")
+ @OptIn(ExperimentalCoroutinesApi::class)
override fun configurationClicked(v: View, configuration: WrenchConfigurationWithValues) {
if (model.selectedScopeLiveData.value == null) {
Snackbar.make(binding.animator, "No selected scope found", Snackbar.LENGTH_LONG).show()
@@ -249,17 +261,42 @@ class ConfigurationsFragment :
val selectedScopeId = model.selectedScopeLiveData.value!!.id
- if (TextUtils.equals(String::class.java.name, configuration.type) || TextUtils.equals(Bolt.TYPE.STRING, configuration.type)
+ if (TextUtils.equals(
+ String::class.java.name,
+ configuration.type
+ ) || TextUtils.equals(Toggle.TYPE.STRING, configuration.type)
) {
- v.findNavController().navigate(
- ConfigurationsFragmentDirections.actionConfigurationsFragmentToStringValueFragment(
- configuration.id,
- selectedScopeId
- )
- )
+ viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
+ toggleFlow(
+ requireContext(),
+ "Use autocomplete in String configurations",
+ false
+ ).first { autoCompleteEnabled ->
+ if (autoCompleteEnabled) {
+ launch(Dispatchers.Main) {
+ v.findNavController().navigate(
+ ConfigurationsFragmentDirections.actionConfigurationsFragmentToAutoCompleteStringValueFragment(
+ configuration.id,
+ selectedScopeId
+ )
+ )
+ }
+ } else {
+ launch(Dispatchers.Main) {
+ v.findNavController().navigate(
+ ConfigurationsFragmentDirections.actionConfigurationsFragmentToStringValueFragment(
+ configuration.id,
+ selectedScopeId
+ )
+ )
+ }
+ }
+ autoCompleteEnabled
+ }
+ }
} else if (TextUtils.equals(Int::class.java.name, configuration.type) || TextUtils.equals(
- Bolt.TYPE.INTEGER,
+ Toggle.TYPE.INTEGER,
configuration.type
)
) {
@@ -273,9 +310,8 @@ class ConfigurationsFragment :
} else if (TextUtils.equals(
Boolean::class.java.name,
configuration.type
- ) || TextUtils.equals(Bolt.TYPE.BOOLEAN, configuration.type)
+ ) || TextUtils.equals(Toggle.TYPE.BOOLEAN, configuration.type)
) {
-
v.findNavController().navigate(
ConfigurationsFragmentDirections.actionConfigurationsFragmentToBooleanValueFragment(
configuration.id,
@@ -283,7 +319,7 @@ class ConfigurationsFragment :
)
)
} else if (TextUtils.equals(Enum::class.java.name, configuration.type) || TextUtils.equals(
- Bolt.TYPE.ENUM,
+ Toggle.TYPE.ENUM,
configuration.type
)
) {
diff --git a/toggles-app/src/main/java/com/izettle/wrench/database/WrenchConfigurationDao.kt b/toggles-app/src/main/java/com/izettle/wrench/database/WrenchConfigurationDao.kt
index ea1ae6a5..40d08024 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/database/WrenchConfigurationDao.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/database/WrenchConfigurationDao.kt
@@ -23,7 +23,7 @@ interface WrenchConfigurationDao {
" INNER JOIN " + ConfigurationValueTable.TABLE_NAME + " ON configuration.id = configurationValue.configurationId " +
" WHERE configuration.id = (:configurationId) AND configurationValue.scope = (:scopeId)"
)
- fun getBolt(configurationId: Long, scopeId: Long): Cursor
+ fun getToggle(configurationId: Long, scopeId: Long): Cursor
@Query(
"SELECT configuration.id, " +
@@ -34,7 +34,7 @@ interface WrenchConfigurationDao {
" INNER JOIN " + ConfigurationValueTable.TABLE_NAME + " ON configuration.id = configurationValue.configurationId " +
" WHERE configuration.configurationKey = (:configurationKey) AND configurationValue.scope = (:scopeId)"
)
- fun getBolt(configurationKey: String, scopeId: Long): Cursor
+ fun getToggle(configurationKey: String, scopeId: Long): Cursor
@Query(
"SELECT * " +
diff --git a/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationTable.kt b/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationTable.kt
index c18ec2f2..2f9cea27 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationTable.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationTable.kt
@@ -1,13 +1,13 @@
package com.izettle.wrench.database.tables
-import com.izettle.wrench.core.ColumnNames
+import se.eelde.toggles.core.ColumnNames
interface ConfigurationTable {
companion object {
const val TABLE_NAME = "configuration"
- const val COL_ID = ColumnNames.Bolt.COL_ID
+ const val COL_ID = ColumnNames.Toggle.COL_ID
const val COL_APP_ID = "applicationId"
- const val COL_KEY = ColumnNames.Bolt.COL_KEY
- const val COL_TYPE = ColumnNames.Bolt.COL_TYPE
+ const val COL_KEY = ColumnNames.Toggle.COL_KEY
+ const val COL_TYPE = ColumnNames.Toggle.COL_TYPE
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationValueTable.kt b/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationValueTable.kt
index 7ae1e4cd..0ac3c06c 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationValueTable.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/database/tables/ConfigurationValueTable.kt
@@ -1,13 +1,13 @@
package com.izettle.wrench.database.tables
-import com.izettle.wrench.core.ColumnNames
+import se.eelde.toggles.core.ColumnNames
interface ConfigurationValueTable {
companion object {
const val TABLE_NAME = "configurationValue"
- const val COL_ID = ColumnNames.Bolt.COL_ID
+ const val COL_ID = ColumnNames.Toggle.COL_ID
const val COL_CONFIG_ID = "configurationId"
- const val COL_VALUE = ColumnNames.Bolt.COL_VALUE
+ const val COL_VALUE = ColumnNames.Toggle.COL_VALUE
const val COL_SCOPE = "scope"
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/database/tables/PredefinedConfigurationValueTable.kt b/toggles-app/src/main/java/com/izettle/wrench/database/tables/PredefinedConfigurationValueTable.kt
index 46b86ec5..5bb367a0 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/database/tables/PredefinedConfigurationValueTable.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/database/tables/PredefinedConfigurationValueTable.kt
@@ -1,13 +1,13 @@
package com.izettle.wrench.database.tables
-import com.izettle.wrench.core.ColumnNames
+import se.eelde.toggles.core.ColumnNames
interface PredefinedConfigurationValueTable {
companion object {
const val TABLE_NAME = "predefinedConfigurationValue"
- const val COL_ID = ColumnNames.Nut.COL_ID
- const val COL_CONFIG_ID = ColumnNames.Nut.COL_CONFIG_ID
- const val COL_VALUE = ColumnNames.Nut.COL_VALUE
+ const val COL_ID = ColumnNames.ToggleValue.COL_ID
+ const val COL_CONFIG_ID = ColumnNames.ToggleValue.COL_CONFIG_ID
+ const val COL_VALUE = ColumnNames.ToggleValue.COL_VALUE
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/autocompletestringvalue/AutoCompleteStringValueFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/autocompletestringvalue/AutoCompleteStringValueFragment.kt
new file mode 100644
index 00000000..861e16ed
--- /dev/null
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/autocompletestringvalue/AutoCompleteStringValueFragment.kt
@@ -0,0 +1,71 @@
+package com.izettle.wrench.dialogs.autocompletestringvalue
+
+import android.app.Dialog
+import android.os.Bundle
+import android.view.View
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.fragment.app.viewModels
+import dagger.hilt.android.AndroidEntryPoint
+import se.eelde.toggles.databinding.FragmentAutocompleteStringValueBinding
+import se.eelde.toggles.viewLifecycle
+
+@AndroidEntryPoint
+class AutoCompleteStringValueFragment : DialogFragment() {
+
+ private var binding: FragmentAutocompleteStringValueBinding by viewLifecycle()
+ private val viewModel by viewModels()
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ this.binding = FragmentAutocompleteStringValueBinding.inflate(layoutInflater)
+
+ viewModel.viewState.observe(
+ this,
+ { viewState ->
+ if (viewState != null) {
+ val invisible = (this.binding.container.visibility == View.INVISIBLE)
+ if (binding.container.visibility == View.INVISIBLE && viewState.title != null) {
+ binding.container.visibility = View.VISIBLE
+ }
+ binding.title.text = viewState.title
+
+ if (invisible) {
+ binding.value.jumpDrawablesToCurrentState()
+ }
+
+ if (viewState.saving || viewState.reverting) {
+ binding.value.isEnabled = false
+ binding.save.isEnabled = false
+ binding.revert.isEnabled = false
+ }
+ }
+ }
+ )
+
+ viewModel.viewEffects.observe(
+ this,
+ { viewEffect ->
+ if (viewEffect != null) {
+ viewEffect.getContentIfNotHandled()?.let { contentIfNotHandled ->
+ when (contentIfNotHandled) {
+ ViewEffect.Dismiss -> dismiss()
+ is ViewEffect.ValueChanged -> binding.value.setText(contentIfNotHandled.value)
+ }
+ }
+ }
+ }
+ )
+
+ binding.revert.setOnClickListener {
+ viewModel.revertClick()
+ }
+
+ binding.save.setOnClickListener {
+ viewModel.saveClick(binding.value.text.toString())
+ }
+
+ return AlertDialog.Builder(requireActivity())
+ .setView(binding.root)
+ .create()
+ }
+}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/autocompletestringvalue/AutoCompleteStringValueFragmentViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/autocompletestringvalue/AutoCompleteStringValueFragmentViewModel.kt
new file mode 100644
index 00000000..31cd1819
--- /dev/null
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/autocompletestringvalue/AutoCompleteStringValueFragmentViewModel.kt
@@ -0,0 +1,162 @@
+package com.izettle.wrench.dialogs.autocompletestringvalue
+
+import android.app.Application
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.asLiveData
+import androidx.lifecycle.viewModelScope
+import com.izettle.wrench.Event
+import com.izettle.wrench.database.WrenchConfigurationDao
+import com.izettle.wrench.database.WrenchConfigurationValue
+import com.izettle.wrench.database.WrenchConfigurationValueDao
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.consumeAsFlow
+import kotlinx.coroutines.launch
+import se.eelde.toggles.core.TogglesProviderContract
+import se.eelde.toggles.provider.notifyUpdate
+import java.util.Date
+import javax.inject.Inject
+
+@HiltViewModel
+class FragmentStringValueViewModel @Inject internal constructor(
+ private val savedStateHandle: SavedStateHandle,
+ private val application: Application,
+ private val configurationDao: WrenchConfigurationDao,
+ private val configurationValueDao: WrenchConfigurationValueDao
+) : ViewModel() {
+
+ private val intentChannel = Channel(Channel.UNLIMITED)
+
+ private val _state = MutableStateFlow(reduce(ViewState(), PartialViewState.Empty))
+
+ private val state: StateFlow
+ get() = _state
+
+ private val configurationId: Long = savedStateHandle.get("configurationId")!!
+ private val scopeId: Long = savedStateHandle.get("scopeId")!!
+
+ private var selectedConfigurationValue: WrenchConfigurationValue? = null
+
+ internal val viewState = state.asLiveData()
+
+ internal val viewEffects = MutableLiveData>()
+
+ init {
+ viewModelScope.launch {
+ intentChannel.consumeAsFlow().collect { viewAction ->
+ when (viewAction) {
+ is ViewAction.SaveAction -> {
+ _state.value = reduce(viewState.value!!, PartialViewState.Saving)
+ updateConfigurationValue(viewAction.value).join()
+ viewEffects.value = Event(ViewEffect.Dismiss)
+ }
+ ViewAction.RevertAction -> {
+ _state.value = reduce(viewState.value!!, PartialViewState.Reverting)
+ deleteConfigurationValue()
+ viewEffects.value = Event(ViewEffect.Dismiss)
+ }
+ }
+ }
+ }
+
+ viewModelScope.launch {
+ configurationDao.getConfiguration(configurationId).collect {
+ _state.value = reduce(viewState.value!!, PartialViewState.NewConfiguration(it.key))
+ }
+ }
+ viewModelScope.launch {
+ configurationValueDao.getConfigurationValue(configurationId, scopeId).collect {
+ if (it != null) {
+ selectedConfigurationValue = it
+ viewEffects.value = Event(ViewEffect.ValueChanged(it.value!!))
+ }
+ }
+ }
+ }
+
+ private fun reduce(previousState: ViewState, partialViewState: PartialViewState): ViewState {
+ return when (partialViewState) {
+ is PartialViewState.NewConfiguration -> {
+ previousState.copy(title = partialViewState.title)
+ }
+ is PartialViewState.Empty -> {
+ previousState
+ }
+ is PartialViewState.Saving -> {
+ previousState.copy(saving = true)
+ }
+ is PartialViewState.Reverting -> {
+ previousState.copy(reverting = true)
+ }
+ }
+ }
+
+ internal fun saveClick(value: String) {
+ intentChannel.offer(ViewAction.SaveAction(value))
+ }
+
+ internal fun revertClick() {
+ intentChannel.offer(ViewAction.RevertAction)
+ }
+
+ private suspend fun updateConfigurationValue(value: String): Job = coroutineScope {
+ viewModelScope.launch(Dispatchers.IO) {
+ if (selectedConfigurationValue != null) {
+ configurationValueDao.updateConfigurationValue(configurationId, scopeId, value)
+ } else {
+ val wrenchConfigurationValue =
+ WrenchConfigurationValue(0, configurationId, value, scopeId)
+ wrenchConfigurationValue.id = configurationValueDao.insert(wrenchConfigurationValue)
+ }
+ configurationDao.touch(configurationId, Date())
+
+ application.contentResolver.notifyUpdate(TogglesProviderContract.toggleUri(configurationId))
+ }
+ }
+
+ private suspend fun deleteConfigurationValue(): Job = coroutineScope {
+ viewModelScope.launch(Dispatchers.IO) {
+ selectedConfigurationValue?.let {
+ configurationValueDao.delete(it)
+
+ application.contentResolver.notifyUpdate(
+ TogglesProviderContract.toggleUri(
+ configurationId
+ )
+ )
+ }
+ }
+ }
+}
+
+internal sealed class ViewAction {
+ data class SaveAction(val value: String) : ViewAction()
+ object RevertAction : ViewAction()
+}
+
+internal sealed class ViewEffect {
+ object Dismiss : ViewEffect()
+ data class ValueChanged(val value: String) : ViewEffect()
+}
+
+internal data class ViewState(
+ val title: String? = null,
+ val saving: Boolean = false,
+ val reverting: Boolean = false
+)
+
+private sealed class PartialViewState {
+ object Empty : PartialViewState()
+ data class NewConfiguration(val title: String?) : PartialViewState()
+
+ object Saving : PartialViewState()
+ object Reverting : PartialViewState()
+}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/BooleanValueFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/BooleanValueFragment.kt
index 3b1229e0..1b7aadfa 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/BooleanValueFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/BooleanValueFragment.kt
@@ -7,10 +7,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import se.eelde.toggles.databinding.FragmentBooleanValueBinding
-@ExperimentalCoroutinesApi
@AndroidEntryPoint
class BooleanValueFragment : DialogFragment() {
@@ -70,13 +68,4 @@ class BooleanValueFragment : DialogFragment() {
.setView(binding.root)
.create()
}
-
- companion object {
-
- fun newInstance(args: BooleanValueFragmentArgs): BooleanValueFragment {
- val fragment = BooleanValueFragment()
- fragment.arguments = args.toBundle()
- return fragment
- }
- }
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/FragmentBooleanValueViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/FragmentBooleanValueViewModel.kt
index 53e354af..698275ee 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/FragmentBooleanValueViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/booleanvalue/FragmentBooleanValueViewModel.kt
@@ -1,7 +1,6 @@
package com.izettle.wrench.dialogs.booleanvalue
+
import android.app.Application
-import androidx.hilt.Assisted
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@@ -11,8 +10,8 @@ import com.izettle.wrench.Event
import com.izettle.wrench.database.WrenchConfigurationDao
import com.izettle.wrench.database.WrenchConfigurationValue
import com.izettle.wrench.database.WrenchConfigurationValueDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
@@ -24,11 +23,11 @@ import kotlinx.coroutines.launch
import se.eelde.toggles.core.TogglesProviderContract
import se.eelde.toggles.provider.notifyUpdate
import java.util.Date
+import javax.inject.Inject
-@ExperimentalCoroutinesApi
-class FragmentBooleanValueViewModel
-@ViewModelInject internal constructor(
- @Assisted private val savedStateHandle: SavedStateHandle,
+@HiltViewModel
+class FragmentBooleanValueViewModel @Inject internal constructor(
+ private val savedStateHandle: SavedStateHandle,
private val application: Application,
private val configurationDao: WrenchConfigurationDao,
private val configurationValueDao: WrenchConfigurationValueDao
@@ -113,12 +112,13 @@ class FragmentBooleanValueViewModel
if (selectedConfigurationValue != null) {
configurationValueDao.updateConfigurationValue(configurationId, scopeId, value)
} else {
- val wrenchConfigurationValue = WrenchConfigurationValue(0, configurationId, value, scopeId)
+ val wrenchConfigurationValue =
+ WrenchConfigurationValue(0, configurationId, value, scopeId)
wrenchConfigurationValue.id = configurationValueDao.insert(wrenchConfigurationValue)
}
configurationDao.touch(configurationId, Date())
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(TogglesProviderContract.toggleUri(configurationId))
}
}
@@ -127,7 +127,11 @@ class FragmentBooleanValueViewModel
selectedConfigurationValue?.let {
configurationValueDao.delete(it)
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(
+ TogglesProviderContract.toggleUri(
+ configurationId
+ )
+ )
}
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/EnumValueFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/EnumValueFragment.kt
index 4538201f..6637038f 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/EnumValueFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/EnumValueFragment.kt
@@ -11,10 +11,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.izettle.wrench.database.WrenchPredefinedConfigurationValue
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import se.eelde.toggles.databinding.FragmentEnumValueBinding
-@ExperimentalCoroutinesApi
@AndroidEntryPoint
class EnumValueFragment : DialogFragment(), PredefinedValueRecyclerViewAdapter.Listener {
@@ -82,13 +80,4 @@ class EnumValueFragment : DialogFragment(), PredefinedValueRecyclerViewAdapter.L
viewModel.saveClick(item.value!!)
dismiss()
}
-
- companion object {
-
- fun newInstance(args: EnumValueFragmentArgs): EnumValueFragment {
- val fragment = EnumValueFragment()
- fragment.arguments = args.toBundle()
- return fragment
- }
- }
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/FragmentEnumValueViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/FragmentEnumValueViewModel.kt
index b9d590fa..326ba704 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/FragmentEnumValueViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/FragmentEnumValueViewModel.kt
@@ -1,8 +1,6 @@
package com.izettle.wrench.dialogs.enumvalue
import android.app.Application
-import androidx.hilt.Assisted
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
@@ -15,8 +13,8 @@ import com.izettle.wrench.database.WrenchConfigurationValue
import com.izettle.wrench.database.WrenchConfigurationValueDao
import com.izettle.wrench.database.WrenchPredefinedConfigurationValue
import com.izettle.wrench.database.WrenchPredefinedConfigurationValueDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
@@ -29,10 +27,11 @@ import se.eelde.toggles.core.TogglesProviderContract
import se.eelde.toggles.provider.notifyInsert
import se.eelde.toggles.provider.notifyUpdate
import java.util.Date
+import javax.inject.Inject
-@ExperimentalCoroutinesApi
-class FragmentEnumValueViewModel @ViewModelInject internal constructor(
- @Assisted private val savedStateHandle: SavedStateHandle,
+@HiltViewModel
+class FragmentEnumValueViewModel @Inject internal constructor(
+ private val savedStateHandle: SavedStateHandle,
private val application: Application,
private val configurationDao: WrenchConfigurationDao,
private val configurationValueDao: WrenchConfigurationValueDao,
@@ -67,14 +66,22 @@ class FragmentEnumValueViewModel @ViewModelInject internal constructor(
is ViewAction.SaveAction -> {
_state.value = reduce(viewState.value!!, PartialViewState.Saving)
updateConfigurationValue(viewAction.value).join()
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(
+ TogglesProviderContract.toggleUri(
+ configurationId
+ )
+ )
viewEffects.value = Event(ViewEffect.Dismiss)
}
ViewAction.RevertAction -> {
_state.value = reduce(viewState.value!!, PartialViewState.Reverting)
deleteConfigurationValue().join()
- application.contentResolver.notifyInsert(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyInsert(
+ TogglesProviderContract.toggleUri(
+ configurationId
+ )
+ )
viewEffects.value = Event(ViewEffect.Dismiss)
}
@@ -126,12 +133,13 @@ class FragmentEnumValueViewModel @ViewModelInject internal constructor(
if (selectedConfigurationValue != null) {
configurationValueDao.updateConfigurationValue(configurationId, scopeId, value)
} else {
- val wrenchConfigurationValue = WrenchConfigurationValue(0, configurationId, value, scopeId)
+ val wrenchConfigurationValue =
+ WrenchConfigurationValue(0, configurationId, value, scopeId)
wrenchConfigurationValue.id = configurationValueDao.insert(wrenchConfigurationValue)
}
configurationDao.touch(configurationId, Date())
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(TogglesProviderContract.toggleUri(configurationId))
}
}
@@ -139,7 +147,7 @@ class FragmentEnumValueViewModel @ViewModelInject internal constructor(
viewModelScope.launch(Dispatchers.IO) {
configurationValueDao.delete(selectedConfigurationValue!!)
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(TogglesProviderContract.toggleUri(configurationId))
}
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/PredefinedValueRecyclerViewAdapter.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/PredefinedValueRecyclerViewAdapter.kt
index 6528e685..dba956b0 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/PredefinedValueRecyclerViewAdapter.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/enumvalue/PredefinedValueRecyclerViewAdapter.kt
@@ -36,7 +36,8 @@ class PredefinedValueRecyclerViewAdapter internal constructor(
fun onClick(view: View, item: WrenchPredefinedConfigurationValue)
}
- inner class ViewHolder(val binding: SimpleListItemBinding) : RecyclerView.ViewHolder(binding.root)
+ inner class ViewHolder(val binding: SimpleListItemBinding) :
+ RecyclerView.ViewHolder(binding.root)
companion object {
private val DIFF_CALLBACK =
@@ -44,16 +45,12 @@ class PredefinedValueRecyclerViewAdapter internal constructor(
override fun areItemsTheSame(
oldApplication: WrenchPredefinedConfigurationValue,
newApplication: WrenchPredefinedConfigurationValue
- ): Boolean {
- return oldApplication.id == newApplication.id
- }
+ ) = oldApplication.id == newApplication.id
override fun areContentsTheSame(
oldApplication: WrenchPredefinedConfigurationValue,
newApplication: WrenchPredefinedConfigurationValue
- ): Boolean {
- return oldApplication == newApplication
- }
+ ) = oldApplication == newApplication
}
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/FragmentIntegerValueViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/FragmentIntegerValueViewModel.kt
index 93bab0eb..4b9a9bde 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/FragmentIntegerValueViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/FragmentIntegerValueViewModel.kt
@@ -1,8 +1,6 @@
package com.izettle.wrench.dialogs.integervalue
import android.app.Application
-import androidx.hilt.Assisted
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@@ -12,8 +10,8 @@ import com.izettle.wrench.Event
import com.izettle.wrench.database.WrenchConfigurationDao
import com.izettle.wrench.database.WrenchConfigurationValue
import com.izettle.wrench.database.WrenchConfigurationValueDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
@@ -25,11 +23,11 @@ import kotlinx.coroutines.launch
import se.eelde.toggles.core.TogglesProviderContract
import se.eelde.toggles.provider.notifyUpdate
import java.util.Date
+import javax.inject.Inject
-@ExperimentalCoroutinesApi
-class FragmentIntegerValueViewModel
-@ViewModelInject internal constructor(
- @Assisted private val savedStateHandle: SavedStateHandle,
+@HiltViewModel
+class FragmentIntegerValueViewModel @Inject internal constructor(
+ private val savedStateHandle: SavedStateHandle,
private val application: Application,
private val configurationDao: WrenchConfigurationDao,
private val configurationValueDao: WrenchConfigurationValueDao
@@ -114,12 +112,13 @@ class FragmentIntegerValueViewModel
if (selectedConfigurationValue != null) {
configurationValueDao.updateConfigurationValue(configurationId, scopeId, value)
} else {
- val wrenchConfigurationValue = WrenchConfigurationValue(0, configurationId, value, scopeId)
+ val wrenchConfigurationValue =
+ WrenchConfigurationValue(0, configurationId, value, scopeId)
wrenchConfigurationValue.id = configurationValueDao.insert(wrenchConfigurationValue)
}
configurationDao.touch(configurationId, Date())
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(TogglesProviderContract.toggleUri(configurationId))
}
}
@@ -128,7 +127,11 @@ class FragmentIntegerValueViewModel
selectedConfigurationValue?.let {
configurationValueDao.delete(it)
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(
+ TogglesProviderContract.toggleUri(
+ configurationId
+ )
+ )
}
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/IntegerValueFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/IntegerValueFragment.kt
index 5126a673..d2a43212 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/IntegerValueFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/integervalue/IntegerValueFragment.kt
@@ -7,10 +7,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import se.eelde.toggles.databinding.FragmentIntegerValueBinding
-@ExperimentalCoroutinesApi
@AndroidEntryPoint
class IntegerValueFragment : DialogFragment() {
@@ -69,13 +67,4 @@ class IntegerValueFragment : DialogFragment() {
.setView(binding.root)
.create()
}
-
- companion object {
-
- fun newInstance(args: IntegerValueFragmentArgs): IntegerValueFragment {
- val fragment = IntegerValueFragment()
- fragment.arguments = args.toBundle()
- return fragment
- }
- }
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/scope/ScopeFragmentViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/scope/ScopeFragmentViewModel.kt
index 06832655..5b42bbed 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/scope/ScopeFragmentViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/scope/ScopeFragmentViewModel.kt
@@ -1,17 +1,21 @@
package com.izettle.wrench.dialogs.scope
import android.database.sqlite.SQLiteException
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.izettle.wrench.database.WrenchScope
import com.izettle.wrench.database.WrenchScopeDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import java.util.Date
+import javax.inject.Inject
+
+@HiltViewModel
+class ScopeFragmentViewModel @Inject internal constructor(
+ private val scopeDao: WrenchScopeDao
+) : ViewModel() {
-class ScopeFragmentViewModel
-@ViewModelInject internal constructor(private val scopeDao: WrenchScopeDao) : ViewModel() {
private var applicationId: Long = 0
internal val selectedScopeLiveData: LiveData by lazy {
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragment.kt
index 4ec5c121..54cf21b7 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragment.kt
@@ -7,10 +7,8 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import se.eelde.toggles.databinding.FragmentStringValueBinding
-@ExperimentalCoroutinesApi
@AndroidEntryPoint
class StringValueFragment : DialogFragment() {
@@ -69,13 +67,4 @@ class StringValueFragment : DialogFragment() {
.setView(binding.root)
.create()
}
-
- companion object {
-
- fun newInstance(args: StringValueFragmentArgs): StringValueFragment {
- val fragment = StringValueFragment()
- fragment.arguments = args.toBundle()
- return fragment
- }
- }
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/FragmentStringValueViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragmentViewModel.kt
similarity index 90%
rename from toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/FragmentStringValueViewModel.kt
rename to toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragmentViewModel.kt
index 509824e3..e7d228c7 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/FragmentStringValueViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/dialogs/stringvalue/StringValueFragmentViewModel.kt
@@ -1,8 +1,6 @@
package com.izettle.wrench.dialogs.stringvalue
import android.app.Application
-import androidx.hilt.Assisted
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@@ -12,8 +10,8 @@ import com.izettle.wrench.Event
import com.izettle.wrench.database.WrenchConfigurationDao
import com.izettle.wrench.database.WrenchConfigurationValue
import com.izettle.wrench.database.WrenchConfigurationValueDao
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
@@ -25,11 +23,12 @@ import kotlinx.coroutines.launch
import se.eelde.toggles.core.TogglesProviderContract
import se.eelde.toggles.provider.notifyUpdate
import java.util.Date
+import javax.inject.Inject
-@ExperimentalCoroutinesApi
+@HiltViewModel
class FragmentStringValueViewModel
-@ViewModelInject internal constructor(
- @Assisted private val savedStateHandle: SavedStateHandle,
+@Inject internal constructor(
+ private val savedStateHandle: SavedStateHandle,
private val application: Application,
private val configurationDao: WrenchConfigurationDao,
private val configurationValueDao: WrenchConfigurationValueDao
@@ -114,12 +113,13 @@ class FragmentStringValueViewModel
if (selectedConfigurationValue != null) {
configurationValueDao.updateConfigurationValue(configurationId, scopeId, value)
} else {
- val wrenchConfigurationValue = WrenchConfigurationValue(0, configurationId, value, scopeId)
+ val wrenchConfigurationValue =
+ WrenchConfigurationValue(0, configurationId, value, scopeId)
wrenchConfigurationValue.id = configurationValueDao.insert(wrenchConfigurationValue)
}
configurationDao.touch(configurationId, Date())
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(TogglesProviderContract.toggleUri(configurationId))
}
}
@@ -128,7 +128,11 @@ class FragmentStringValueViewModel
selectedConfigurationValue?.let {
configurationValueDao.delete(it)
- application.contentResolver.notifyUpdate(TogglesProviderContract.boltUri(configurationId))
+ application.contentResolver.notifyUpdate(
+ TogglesProviderContract.toggleUri(
+ configurationId
+ )
+ )
}
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/help/HelpFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/help/HelpFragment.kt
index 9c78efe2..14a132bc 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/help/HelpFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/help/HelpFragment.kt
@@ -4,12 +4,21 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import se.eelde.toggles.R
+import se.eelde.toggles.help.HelpView
class HelpFragment : Fragment() {
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return inflater.inflate(R.layout.fragment_help, container, false)
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return inflater.inflate(R.layout.fragment_help, container, false).apply {
+ findViewById(R.id.compose).setContent {
+ HelpView()
+ }
+ }
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/oss/detail/LicenceMetadataLiveData.kt b/toggles-app/src/main/java/com/izettle/wrench/oss/detail/LicenceMetadataLiveData.kt
index cae41544..c6f71094 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/oss/detail/LicenceMetadataLiveData.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/oss/detail/LicenceMetadataLiveData.kt
@@ -5,7 +5,7 @@ import androidx.lifecycle.LiveData
import com.izettle.wrench.oss.LicenceMetadata
import com.izettle.wrench.oss.list.OssLoading
-class LicenceMetadataLiveData(val context: Context, val licenceMetadata: LicenceMetadata) : LiveData() {
+class LicenceMetadataLiveData(val context: Context, private val licenceMetadata: LicenceMetadata) : LiveData() {
init {
run {
diff --git a/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailFragment.kt b/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailFragment.kt
index 991d5f67..2377281f 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailFragment.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailFragment.kt
@@ -1,11 +1,12 @@
package com.izettle.wrench.oss.detail
-import android.app.Dialog
import android.os.Bundle
import android.text.util.Linkify
-import androidx.appcompat.app.AlertDialog
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
import androidx.core.text.util.LinkifyCompat
-import androidx.fragment.app.DialogFragment
+import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.navArgs
import com.izettle.wrench.oss.LicenceMetadata
@@ -13,35 +14,29 @@ import dagger.hilt.android.AndroidEntryPoint
import se.eelde.toggles.databinding.FragmentOssDetailBinding
@AndroidEntryPoint
-class OssDetailFragment : DialogFragment() {
+class OssDetailFragment : Fragment() {
private lateinit var binding: FragmentOssDetailBinding
private val viewModel by viewModels()
private val args: OssDetailFragmentArgs by navArgs()
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
-
- val root = FragmentOssDetailBinding.inflate(layoutInflater).also {
- binding = it
- }.root
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ) = FragmentOssDetailBinding.inflate(layoutInflater).also {
+ binding = it
+ }.root
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val licenceMetadata = LicenceMetadata(args.dependency, args.skip.toLong(), args.length)
- viewModel.getThirdPartyMetadata(licenceMetadata).observe(
- this,
- {
- binding.text.text = it
- LinkifyCompat.addLinks(binding.text, Linkify.WEB_URLS)
- }
- )
-
- return AlertDialog.Builder(requireActivity())
- .setTitle(licenceMetadata.dependency)
- .setView(root)
- .setPositiveButton("dismiss") { _, _ ->
- dismiss()
- }
- .create()
+ binding.title.text = licenceMetadata.dependency
+
+ viewModel.getThirdPartyMetadata(licenceMetadata).observe(viewLifecycleOwner) {
+ binding.text.text = it
+ LinkifyCompat.addLinks(binding.text, Linkify.WEB_URLS)
+ }
}
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailViewModel.kt
index 3f932a71..107bffa1 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/oss/detail/OssDetailViewModel.kt
@@ -1,12 +1,14 @@
package com.izettle.wrench.oss.detail
import android.app.Application
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.izettle.wrench.oss.LicenceMetadata
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
-class OssDetailViewModel @ViewModelInject internal constructor(val application: Application) : ViewModel() {
+@HiltViewModel
+class OssDetailViewModel @Inject internal constructor(val application: Application) : ViewModel() {
fun getThirdPartyMetadata(licenceMetadata: LicenceMetadata): LiveData {
return LicenceMetadataLiveData(application, licenceMetadata)
diff --git a/toggles-app/src/main/java/com/izettle/wrench/oss/list/OssListViewModel.kt b/toggles-app/src/main/java/com/izettle/wrench/oss/list/OssListViewModel.kt
index 6708d954..efafeb95 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/oss/list/OssListViewModel.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/oss/list/OssListViewModel.kt
@@ -1,12 +1,14 @@
package com.izettle.wrench.oss.list
import android.app.Application
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import com.izettle.wrench.oss.LicenceMetadata
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
-class OssListViewModel @ViewModelInject internal constructor(val application: Application) : ViewModel() {
+@HiltViewModel
+class OssListViewModel @Inject internal constructor(val application: Application) : ViewModel() {
fun getThirdPartyMetadata(): LiveData> {
return ThirdPartyLicenceMetadataLiveData(application)
}
diff --git a/toggles-app/src/main/java/com/izettle/wrench/provider/WrenchProvider.kt b/toggles-app/src/main/java/com/izettle/wrench/provider/WrenchProvider.kt
index fdcc6a51..22a1eb44 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/provider/WrenchProvider.kt
+++ b/toggles-app/src/main/java/com/izettle/wrench/provider/WrenchProvider.kt
@@ -28,13 +28,14 @@ import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
+import kotlinx.coroutines.GlobalScope
import se.eelde.toggles.BuildConfig
import se.eelde.toggles.TogglesUriMatcher
import se.eelde.toggles.TogglesUriMatcher.Companion.CURRENT_CONFIGURATIONS
import se.eelde.toggles.TogglesUriMatcher.Companion.CURRENT_CONFIGURATION_ID
import se.eelde.toggles.TogglesUriMatcher.Companion.CURRENT_CONFIGURATION_KEY
import se.eelde.toggles.TogglesUriMatcher.Companion.PREDEFINED_CONFIGURATION_VALUES
-import se.eelde.toggles.notification.configurationRequested
+import se.eelde.toggles.notification.ChangedHelper
import se.eelde.toggles.provider.IPackageManagerWrapper
import se.eelde.toggles.provider.notifyInsert
import se.eelde.toggles.provider.notifyUpdate
@@ -74,6 +75,10 @@ class WrenchProvider : ContentProvider() {
applicationEntryPoint.providesWrenchPreferences()
}
+ private val changedHelper: ChangedHelper by lazy {
+ applicationEntryPoint.providerChangedHelper()
+ }
+
private val applicationEntryPoint: WrenchProviderEntryPoint by lazy {
EntryPointAccessors.fromApplication(context!!, WrenchProviderEntryPoint::class.java)
}
@@ -89,6 +94,7 @@ class WrenchProvider : ContentProvider() {
fun provideTogglesNotificationDao(): TogglesNotificationDao
fun providePackageManagerWrapper(): IPackageManagerWrapper
fun providesWrenchPreferences(): ITogglesPreferences
+ fun providerChangedHelper(): ChangedHelper
}
@Synchronized
@@ -137,7 +143,7 @@ class WrenchProvider : ContentProvider() {
when (uriMatcher.match(uri)) {
CURRENT_CONFIGURATION_ID -> {
val scope = getSelectedScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(
+ cursor = configurationDao.getToggle(
java.lang.Long.valueOf(uri.lastPathSegment!!),
scope!!.id
)
@@ -146,7 +152,7 @@ class WrenchProvider : ContentProvider() {
cursor.close()
val defaultScope = getDefaultScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(
+ cursor = configurationDao.getToggle(
java.lang.Long.valueOf(uri.lastPathSegment!!),
defaultScope!!.id
)
@@ -156,37 +162,37 @@ class WrenchProvider : ContentProvider() {
val bolt = Bolt.fromCursor(cursor)
cursor.moveToPrevious()
context?.apply {
- configurationRequested(
- this,
- configurationDao,
- togglesNotificationDao,
+ changedHelper.configurationRequested(
callingApplication,
- bolt
+ bolt.id,
+ bolt.key,
+ bolt.value,
+ GlobalScope,
)
}
}
}
CURRENT_CONFIGURATION_KEY -> {
val scope = getSelectedScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(uri.lastPathSegment!!, scope!!.id)
+ cursor = configurationDao.getToggle(uri.lastPathSegment!!, scope!!.id)
if (cursor.count == 0) {
cursor.close()
val defaultScope = getDefaultScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(uri.lastPathSegment!!, defaultScope!!.id)
+ cursor = configurationDao.getToggle(uri.lastPathSegment!!, defaultScope!!.id)
}
if (cursor.moveToFirst()) {
val bolt = Bolt.fromCursor(cursor)
cursor.moveToPrevious()
context?.apply {
- configurationRequested(
- this,
- configurationDao,
- togglesNotificationDao,
+ changedHelper.configurationRequested(
callingApplication,
- bolt
+ bolt.id,
+ bolt.key,
+ bolt.value,
+ GlobalScope,
)
}
}
diff --git a/toggles-app/src/main/java/se/eelde/toggles/ViewLifecycle.kt b/toggles-app/src/main/java/se/eelde/toggles/ViewLifecycle.kt
new file mode 100644
index 00000000..a79615e4
--- /dev/null
+++ b/toggles-app/src/main/java/se/eelde/toggles/ViewLifecycle.kt
@@ -0,0 +1,61 @@
+package se.eelde.toggles
+
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.Observer
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
+
+/*
+* Based on https://gist.github.com/jamiesanson/d1a3ed0910cd605e928572ce245bafc4
+*
+* Refactored to use the preferred `DefaultLifecycleObserver` which does not rely on the annotation processor.
+* See https://developer.android.com/reference/kotlin/androidx/lifecycle/Lifecycle#init
+*
+* Usage:
+* `private var binding: TheViewBinding by viewLifecycle()`
+*/
+
+/**
+ * An extension to bind and unbind a value based on the view lifecycle of a Fragment.
+ * The binding will be unbound in onDestroyView.
+ *
+ * @throws IllegalStateException If the getter is invoked before the binding is set,
+ * or after onDestroyView an exception is thrown.
+ */
+fun Fragment.viewLifecycle(): ReadWriteProperty =
+ object : ReadWriteProperty, DefaultLifecycleObserver {
+
+ private var binding: T? = null
+
+ init {
+ // Observe the view lifecycle of the Fragment.
+ // The view lifecycle owner is null before onCreateView and after onDestroyView.
+ // The observer is automatically removed after the onDestroy event.
+ this@viewLifecycle
+ .viewLifecycleOwnerLiveData
+ .observe(this@viewLifecycle, Observer { owner: LifecycleOwner? ->
+ owner?.lifecycle?.addObserver(this)
+ })
+ }
+
+ override fun onDestroy(owner: LifecycleOwner) {
+ binding = null
+ }
+
+ override fun getValue(
+ thisRef: Fragment,
+ property: KProperty<*>
+ ): T {
+ return this.binding ?: error("Called before onCreateView or after onDestroyView.")
+ }
+
+ override fun setValue(
+ thisRef: Fragment,
+ property: KProperty<*>,
+ value: T
+ ) {
+ this.binding = value
+ }
+ }
diff --git a/toggles-app/src/main/java/com/izettle/wrench/di/ApplicationModule.kt b/toggles-app/src/main/java/se/eelde/toggles/di/ApplicationModule.kt
similarity index 97%
rename from toggles-app/src/main/java/com/izettle/wrench/di/ApplicationModule.kt
rename to toggles-app/src/main/java/se/eelde/toggles/di/ApplicationModule.kt
index 443369d5..f1403886 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/di/ApplicationModule.kt
+++ b/toggles-app/src/main/java/se/eelde/toggles/di/ApplicationModule.kt
@@ -1,4 +1,4 @@
-package com.izettle.wrench.di
+package se.eelde.toggles.di
import android.content.Context
import com.izettle.wrench.preferences.ITogglesPreferences
diff --git a/toggles-app/src/main/java/com/izettle/wrench/di/DatabaseModule.kt b/toggles-app/src/main/java/se/eelde/toggles/di/DatabaseModule.kt
similarity index 98%
rename from toggles-app/src/main/java/com/izettle/wrench/di/DatabaseModule.kt
rename to toggles-app/src/main/java/se/eelde/toggles/di/DatabaseModule.kt
index 0fa9230e..7afec340 100644
--- a/toggles-app/src/main/java/com/izettle/wrench/di/DatabaseModule.kt
+++ b/toggles-app/src/main/java/se/eelde/toggles/di/DatabaseModule.kt
@@ -1,4 +1,4 @@
-package com.izettle.wrench.di
+package se.eelde.toggles.di
import android.content.Context
import androidx.room.Room
diff --git a/toggles-app/src/main/java/se/eelde/toggles/help/HelpView.kt b/toggles-app/src/main/java/se/eelde/toggles/help/HelpView.kt
new file mode 100644
index 00000000..667db7d0
--- /dev/null
+++ b/toggles-app/src/main/java/se/eelde/toggles/help/HelpView.kt
@@ -0,0 +1,10 @@
+package se.eelde.toggles.help
+
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+
+@Composable
+fun HelpView() {
+ Text(text = "Implementation", color = Color.White)
+}
diff --git a/toggles-app/src/main/java/se/eelde/toggles/notification/BubbleCompatNotificationHelper.kt b/toggles-app/src/main/java/se/eelde/toggles/notification/BubbleCompatNotificationHelper.kt
index 902edcf9..90d0adcf 100644
--- a/toggles-app/src/main/java/se/eelde/toggles/notification/BubbleCompatNotificationHelper.kt
+++ b/toggles-app/src/main/java/se/eelde/toggles/notification/BubbleCompatNotificationHelper.kt
@@ -1,5 +1,6 @@
package se.eelde.toggles.notification
+import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
@@ -22,6 +23,11 @@ import se.eelde.toggles.R
import se.eelde.toggles.bubble.BubbleActivity
import se.eelde.toggles.core.TogglesProviderContract
+// Since we're not targeting android S we need a local version of this to make a lint check happy
+// https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability
+// https://developer.android.com/reference/android/app/PendingIntent#FLAG_MUTABLE
+const val MUTABILITY_FLAG_FROM_ANDROID_31 = 0x02000000
+
@RequiresApi(Build.VERSION_CODES.R)
class BubbleCompatNotificationHelper(private val context: Context) {
companion object {
@@ -57,6 +63,7 @@ class BubbleCompatNotificationHelper(private val context: Context) {
// updateShortcuts(null)
}
+ @SuppressLint("WrongConstant")
@Suppress("LongMethod")
@WorkerThread
fun showNotification(
@@ -64,11 +71,13 @@ class BubbleCompatNotificationHelper(private val context: Context) {
togglesNotifications: List,
fromUser: Boolean
) {
- val applicationIcon = context.packageManager.getApplicationIcon(wrenchApplication.packageName)
+ val applicationIcon =
+ context.packageManager.getApplicationIcon(wrenchApplication.packageName)
val icon = IconCompat.createWithAdaptiveBitmap(applicationIcon.toBitmap())
val user = Person.Builder().setName(context.getString(R.string.sender_you)).build()
- val person = Person.Builder().setName(wrenchApplication.applicationLabel).setIcon(icon).build()
+ val person =
+ Person.Builder().setName(wrenchApplication.applicationLabel).setIcon(icon).build()
val contentUri = TogglesProviderContract.applicationUri(wrenchApplication.id)
val pendingIntent = PendingIntent.getActivity(
@@ -78,7 +87,7 @@ class BubbleCompatNotificationHelper(private val context: Context) {
Intent(context, BubbleActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.setData(contentUri),
- PendingIntent.FLAG_UPDATE_CURRENT
+ PendingIntent.FLAG_UPDATE_CURRENT or MUTABILITY_FLAG_FROM_ANDROID_31
)
val builder = NotificationCompat.Builder(context, CHANNEL_NEW_MESSAGES)
@@ -119,7 +128,7 @@ class BubbleCompatNotificationHelper(private val context: Context) {
Intent(context, BubbleActivity::class.java)
.setAction(Intent.ACTION_VIEW)
.setData(contentUri),
- PendingIntent.FLAG_UPDATE_CURRENT
+ PendingIntent.FLAG_UPDATE_CURRENT or MUTABILITY_FLAG_FROM_ANDROID_31
)
)
// Direct Reply
@@ -132,7 +141,7 @@ class BubbleCompatNotificationHelper(private val context: Context) {
context,
REQUEST_CONTENT,
Intent(context, BubbleActivity::class.java).setData(contentUri),
- PendingIntent.FLAG_UPDATE_CURRENT
+ PendingIntent.FLAG_UPDATE_CURRENT or MUTABILITY_FLAG_FROM_ANDROID_31
)
)
.addRemoteInput(
diff --git a/toggles-app/src/main/java/se/eelde/toggles/notification/ChangedHelper.kt b/toggles-app/src/main/java/se/eelde/toggles/notification/ChangedHelper.kt
index c8dbbbe3..ed78beaf 100644
--- a/toggles-app/src/main/java/se/eelde/toggles/notification/ChangedHelper.kt
+++ b/toggles-app/src/main/java/se/eelde/toggles/notification/ChangedHelper.kt
@@ -1,33 +1,67 @@
package se.eelde.toggles.notification
import android.content.Context
-import com.izettle.wrench.core.Bolt
import com.izettle.wrench.database.TogglesNotification
import com.izettle.wrench.database.TogglesNotificationDao
import com.izettle.wrench.database.WrenchApplication
import com.izettle.wrench.database.WrenchConfigurationDao
+import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import se.eelde.toggles.core.Toggle
+import se.eelde.toggles.flow.toggleFlow
import java.util.Date
+import javax.inject.Inject
-fun configurationRequested(
- context: Context,
- configurationDao: WrenchConfigurationDao,
- togglesNotificationDao: TogglesNotificationDao,
- application: WrenchApplication,
- bolt: Bolt,
+class ChangedHelper @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val configurationDao: WrenchConfigurationDao,
+ private val togglesNotificationDao: TogglesNotificationDao,
) {
- configurationDao.getWrenchConfigurationById(application.id, bolt.id)
- ?.let { configuration ->
- togglesNotificationDao.insert(
- TogglesNotification(
- applicationId = application.id,
- applicationPackageName = application.packageName,
- configurationId = configuration.id,
- configurationKey = bolt.key,
- configurationValue = bolt.value!!,
- added = Date(),
- )
- )
- }
+ fun configurationRequested(
+ application: WrenchApplication,
+ toggle: Toggle,
+ scope: CoroutineScope
+ ) = configurationRequested(
+ application,
+ toggle.id,
+ toggle.key,
+ toggle.value,
+ scope,
+ )
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ fun configurationRequested(
+ application: WrenchApplication,
+ toggleId: Long,
+ toggleKey: String,
+ toggleValue: String?,
+ scope: CoroutineScope
+ ) {
+ scope.launch(Dispatchers.IO) {
+ val notificationsEnabled =
+ toggleFlow(context, "Enable notifications", false).first()
- NotificationWorker.scheduleNotification(context)
+ if (notificationsEnabled) {
+ configurationDao.getWrenchConfigurationById(application.id, toggleId)
+ ?.let { configuration ->
+ togglesNotificationDao.insert(
+ TogglesNotification(
+ applicationId = application.id,
+ applicationPackageName = application.packageName,
+ configurationId = configuration.id,
+ configurationKey = toggleKey,
+ configurationValue = toggleValue!!,
+ added = Date(),
+ )
+ )
+ }
+
+ NotificationWorker.scheduleNotification(context)
+ }
+ }
+ }
}
diff --git a/toggles-app/src/main/java/se/eelde/toggles/notification/NotificationWorker.kt b/toggles-app/src/main/java/se/eelde/toggles/notification/NotificationWorker.kt
index 814e6821..1fc5e15d 100644
--- a/toggles-app/src/main/java/se/eelde/toggles/notification/NotificationWorker.kt
+++ b/toggles-app/src/main/java/se/eelde/toggles/notification/NotificationWorker.kt
@@ -13,8 +13,7 @@ import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import androidx.core.graphics.drawable.toBitmap
-import androidx.hilt.Assisted
-import androidx.hilt.work.WorkerInject
+import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
@@ -24,21 +23,30 @@ import androidx.work.WorkerParameters
import com.izettle.wrench.MainActivity
import com.izettle.wrench.database.WrenchApplication
import com.izettle.wrench.database.WrenchDatabase
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
import se.eelde.toggles.core.TogglesProviderContract
+import se.eelde.toggles.flow.toggleFlow
import java.util.concurrent.TimeUnit
-class NotificationWorker @WorkerInject constructor(
+@HiltWorker
+class NotificationWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
val wrenchDatabase: WrenchDatabase,
-) :
- CoroutineWorker(appContext, workerParams) {
+) : CoroutineWorker(appContext, workerParams) {
companion object {
- fun scheduleNotification(context: Context) {
+ private const val DEFAULT_NOTIFICATION_DEBOUNCE = 1000
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ suspend fun scheduleNotification(context: Context) {
+ val notificationDebounce = toggleFlow(context, "Toggle request debounce timeout (milliseconds)", DEFAULT_NOTIFICATION_DEBOUNCE).first()
val notificationWorker: OneTimeWorkRequest =
OneTimeWorkRequestBuilder()
- .setInitialDelay(2, TimeUnit.SECONDS)
+ .setInitialDelay(notificationDebounce.toLong(), TimeUnit.MILLISECONDS)
.build()
WorkManager
diff --git a/toggles-app/src/main/java/se/eelde/toggles/provider/TogglesProvider.kt b/toggles-app/src/main/java/se/eelde/toggles/provider/TogglesProvider.kt
index c3511039..cb70c471 100644
--- a/toggles-app/src/main/java/se/eelde/toggles/provider/TogglesProvider.kt
+++ b/toggles-app/src/main/java/se/eelde/toggles/provider/TogglesProvider.kt
@@ -6,9 +6,9 @@ import android.content.ContentValues
import android.content.Context
import android.content.pm.PackageManager
import android.database.Cursor
+import android.database.sqlite.SQLiteConstraintException
import android.net.Uri
import android.os.Binder
-import com.izettle.wrench.core.Bolt
import com.izettle.wrench.database.TogglesNotificationDao
import com.izettle.wrench.database.WrenchApplication
import com.izettle.wrench.database.WrenchApplicationDao
@@ -25,14 +25,16 @@ import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
+import kotlinx.coroutines.GlobalScope
import se.eelde.toggles.BuildConfig
import se.eelde.toggles.TogglesUriMatcher
import se.eelde.toggles.TogglesUriMatcher.Companion.CURRENT_CONFIGURATIONS
import se.eelde.toggles.TogglesUriMatcher.Companion.CURRENT_CONFIGURATION_ID
import se.eelde.toggles.TogglesUriMatcher.Companion.CURRENT_CONFIGURATION_KEY
import se.eelde.toggles.TogglesUriMatcher.Companion.PREDEFINED_CONFIGURATION_VALUES
+import se.eelde.toggles.core.Toggle
import se.eelde.toggles.core.TogglesProviderContract
-import se.eelde.toggles.notification.configurationRequested
+import se.eelde.toggles.notification.ChangedHelper
import java.util.Date
class TogglesProvider : ContentProvider() {
@@ -69,6 +71,10 @@ class TogglesProvider : ContentProvider() {
applicationEntryPoint.providesWrenchPreferences()
}
+ private val changedHelper: ChangedHelper by lazy {
+ applicationEntryPoint.providerChangedHelper()
+ }
+
private val applicationEntryPoint: TogglesProviderEntryPoint by lazy {
EntryPointAccessors.fromApplication(context!!, TogglesProviderEntryPoint::class.java)
}
@@ -84,9 +90,9 @@ class TogglesProvider : ContentProvider() {
fun provideTogglesNotificationDao(): TogglesNotificationDao
fun providePackageManagerWrapper(): IPackageManagerWrapper
fun providesWrenchPreferences(): ITogglesPreferences
+ fun providerChangedHelper(): ChangedHelper
}
- @Synchronized
private fun getCallingApplication(applicationDao: WrenchApplicationDao): WrenchApplication {
var wrenchApplication: WrenchApplication? =
applicationDao.loadByPackageName(packageManagerWrapper.callingApplicationPackageName!!)
@@ -112,7 +118,7 @@ class TogglesProvider : ContentProvider() {
override fun onCreate() = true
- @Suppress("LongMethod")
+ @Suppress("LongMethod", "NestedBlockDepth")
override fun query(
uri: Uri,
projection: Array?,
@@ -131,7 +137,7 @@ class TogglesProvider : ContentProvider() {
when (uriMatcher.match(uri)) {
CURRENT_CONFIGURATION_ID -> {
val scope = getSelectedScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(
+ cursor = configurationDao.getToggle(
java.lang.Long.valueOf(uri.lastPathSegment!!),
scope!!.id
)
@@ -140,48 +146,48 @@ class TogglesProvider : ContentProvider() {
cursor.close()
val defaultScope = getDefaultScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(
+ cursor = configurationDao.getToggle(
java.lang.Long.valueOf(uri.lastPathSegment!!),
defaultScope!!.id
)
}
if (cursor.moveToFirst()) {
- val bolt = Bolt.fromCursor(cursor)
+ val toggle = Toggle.fromCursor(cursor)
cursor.moveToPrevious()
- context?.apply {
- configurationRequested(
- this,
- configurationDao,
- togglesNotificationDao,
- callingApplication,
- bolt
- )
+ if (!isTogglesApplication(callingApplication)) {
+ context?.apply {
+ changedHelper.configurationRequested(
+ callingApplication,
+ toggle,
+ GlobalScope
+ )
+ }
}
}
}
CURRENT_CONFIGURATION_KEY -> {
val scope = getSelectedScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(uri.lastPathSegment!!, scope!!.id)
+ cursor = configurationDao.getToggle(uri.lastPathSegment!!, scope!!.id)
if (cursor.count == 0) {
cursor.close()
val defaultScope = getDefaultScope(context, scopeDao, callingApplication.id)
- cursor = configurationDao.getBolt(uri.lastPathSegment!!, defaultScope!!.id)
+ cursor = configurationDao.getToggle(uri.lastPathSegment!!, defaultScope!!.id)
}
if (cursor.moveToFirst()) {
- val bolt = Bolt.fromCursor(cursor)
+ val toggle = Toggle.fromCursor(cursor)
cursor.moveToPrevious()
- context?.apply {
- configurationRequested(
- this,
- configurationDao,
- togglesNotificationDao,
- callingApplication,
- bolt
- )
+ if (!isTogglesApplication(callingApplication)) {
+ context?.apply {
+ changedHelper.configurationRequested(
+ callingApplication,
+ toggle,
+ GlobalScope
+ )
+ }
}
}
}
@@ -212,14 +218,14 @@ class TogglesProvider : ContentProvider() {
val insertId: Long
when (uriMatcher.match(uri)) {
CURRENT_CONFIGURATIONS -> {
- val bolt = Bolt.fromContentValues(values!!)
+ val toggle = Toggle.fromContentValues(values!!)
var wrenchConfiguration: WrenchConfiguration? =
- configurationDao.getWrenchConfiguration(callingApplication.id, bolt.key)
+ configurationDao.getWrenchConfiguration(callingApplication.id, toggle.key)
if (wrenchConfiguration == null) {
wrenchConfiguration =
- WrenchConfiguration(0, callingApplication.id, bolt.key, bolt.type)
+ WrenchConfiguration(0, callingApplication.id, toggle.key, toggle.type)
wrenchConfiguration.id = configurationDao.insert(wrenchConfiguration)
}
@@ -229,15 +235,19 @@ class TogglesProvider : ContentProvider() {
val wrenchConfigurationValue = WrenchConfigurationValue(
0,
wrenchConfiguration.id,
- bolt.value,
+ toggle.value,
defaultScope!!.id
)
wrenchConfigurationValue.configurationId = wrenchConfiguration.id
- wrenchConfigurationValue.value = bolt.value
+ wrenchConfigurationValue.value = toggle.value
wrenchConfigurationValue.scope = defaultScope.id
- wrenchConfigurationValue.id =
- configurationValueDao.insertSync(wrenchConfigurationValue)
+ try {
+ wrenchConfigurationValue.id =
+ configurationValueDao.insertSync(wrenchConfigurationValue)
+ } catch (e: SQLiteConstraintException) {
+ // this happens when the app is initially launched because many of many calls into assertValidApiVersion()
+ }
insertId = wrenchConfiguration.id
}
@@ -281,18 +291,18 @@ class TogglesProvider : ContentProvider() {
val updatedRows: Int
when (uriMatcher.match(uri)) {
CURRENT_CONFIGURATION_ID -> {
- val bolt = Bolt.fromContentValues(values!!)
+ val toggle = Toggle.fromContentValues(values!!)
val scope = getSelectedScope(context, scopeDao, callingApplication.id)
updatedRows = configurationValueDao.updateConfigurationValueSync(
java.lang.Long.parseLong(uri.lastPathSegment!!),
scope!!.id,
- bolt.value!!
+ toggle.value!!
)
if (updatedRows == 0) {
val wrenchConfigurationValue = WrenchConfigurationValue(
0,
java.lang.Long.parseLong(uri.lastPathSegment!!),
- bolt.value,
+ toggle.value,
scope.id
)
configurationValueDao.insertSync(wrenchConfigurationValue)
@@ -401,6 +411,7 @@ class TogglesProvider : ContentProvider() {
return scope
}
+ @Synchronized
private fun assertValidApiVersion(togglesPreferences: ITogglesPreferences, uri: Uri) {
var l: Long = 0
val strictApiVersion = try {
diff --git a/toggles-app/src/main/res/layout/application_list_item.xml b/toggles-app/src/main/res/layout/application_list_item.xml
index d525faad..e868b1c7 100644
--- a/toggles-app/src/main/res/layout/application_list_item.xml
+++ b/toggles-app/src/main/res/layout/application_list_item.xml
@@ -14,7 +14,6 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/application_icon"
@@ -30,7 +29,6 @@
android:layout_height="21dp"
android:layout_margin="@dimen/text_margin"
android:layout_marginStart="8dp"
- android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:textAppearance="?attr/textAppearanceListItem"
diff --git a/toggles-app/src/main/res/layout/fragment_autocomplete_string_value.xml b/toggles-app/src/main/res/layout/fragment_autocomplete_string_value.xml
new file mode 100644
index 00000000..4632ca8f
--- /dev/null
+++ b/toggles-app/src/main/res/layout/fragment_autocomplete_string_value.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/toggles-app/src/main/res/layout/fragment_help.xml b/toggles-app/src/main/res/layout/fragment_help.xml
index 8ef896a2..e011626f 100644
--- a/toggles-app/src/main/res/layout/fragment_help.xml
+++ b/toggles-app/src/main/res/layout/fragment_help.xml
@@ -1,33 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/toggles-app/src/main/res/layout/fragment_oss_detail.xml b/toggles-app/src/main/res/layout/fragment_oss_detail.xml
index 52cb38f1..46a168d3 100644
--- a/toggles-app/src/main/res/layout/fragment_oss_detail.xml
+++ b/toggles-app/src/main/res/layout/fragment_oss_detail.xml
@@ -3,20 +3,26 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:padding="24dp">
+
+
diff --git a/toggles-app/src/main/res/layout/oss_list_item.xml b/toggles-app/src/main/res/layout/oss_list_item.xml
index d7a8b017..be9a472f 100644
--- a/toggles-app/src/main/res/layout/oss_list_item.xml
+++ b/toggles-app/src/main/res/layout/oss_list_item.xml
@@ -8,8 +8,6 @@
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
tools:text="Test text" />
diff --git a/toggles-app/src/main/res/layout/simple_list_item.xml b/toggles-app/src/main/res/layout/simple_list_item.xml
index 80e31630..8afabd20 100644
--- a/toggles-app/src/main/res/layout/simple_list_item.xml
+++ b/toggles-app/src/main/res/layout/simple_list_item.xml
@@ -8,8 +8,6 @@
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingRight="?android:attr/listPreferredItemPaddingRight"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
tools:text="Test text" />
diff --git a/toggles-app/src/main/res/navigation/application_configurations_graph.xml b/toggles-app/src/main/res/navigation/application_configurations_graph.xml
index e7fac489..ffb9c013 100644
--- a/toggles-app/src/main/res/navigation/application_configurations_graph.xml
+++ b/toggles-app/src/main/res/navigation/application_configurations_graph.xml
@@ -7,14 +7,20 @@
+
+ android:label="{applicationLabel}">
+
@@ -30,6 +36,9 @@
+
@@ -93,5 +102,16 @@
android:name="scopeId"
app:argType="long" />
+
\ No newline at end of file
diff --git a/toggles-app/src/main/res/navigation/navigation_graph.xml b/toggles-app/src/main/res/navigation/navigation_graph.xml
index d95d401c..21eefbb3 100644
--- a/toggles-app/src/main/res/navigation/navigation_graph.xml
+++ b/toggles-app/src/main/res/navigation/navigation_graph.xml
@@ -14,6 +14,9 @@
+
-
-
+
()
+ shadowOf(context.packageManager).setApplicationIcon("se.eelde.toggles", GradientDrawable())
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(SynchronousExecutor())
diff --git a/toggles-app/src/test/java/se/eelde/toggles/db/MigrationTests.kt b/toggles-app/src/test/java/se/eelde/toggles/db/MigrationTests.kt
index 11be06b0..4853da43 100644
--- a/toggles-app/src/test/java/se/eelde/toggles/db/MigrationTests.kt
+++ b/toggles-app/src/test/java/se/eelde/toggles/db/MigrationTests.kt
@@ -5,7 +5,6 @@ import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
-import com.izettle.wrench.core.Bolt
import com.izettle.wrench.database.WrenchDatabase
import com.izettle.wrench.database.migrations.Migrations.MIGRATION_1_2
import com.izettle.wrench.database.migrations.Migrations.MIGRATION_2_3
@@ -17,6 +16,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
+import se.eelde.toggles.core.Toggle
import java.io.IOException
@RunWith(AndroidJUnit4::class)
@@ -53,10 +53,10 @@ class MigrationTests {
val testApplicationId = DatabaseHelper.insertWrenchApplication(originalDb, "TestApplication", "com.izettle.wrench.testapplication")
// insert data
- DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Integerkey", Bolt.TYPE.INTEGER)
- DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Stringkey", Bolt.TYPE.STRING)
- DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Booleankey", Bolt.TYPE.BOOLEAN)
- DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Enumkey", Bolt.TYPE.ENUM)
+ DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Integerkey", Toggle.TYPE.INTEGER)
+ DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Stringkey", Toggle.TYPE.STRING)
+ DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Booleankey", Toggle.TYPE.BOOLEAN)
+ DatabaseHelper.insertWrenchConfiguration(originalDb, testApplicationId, "Enumkey", Toggle.TYPE.ENUM)
originalDb.close()
@@ -64,22 +64,22 @@ class MigrationTests {
var cursor = DatabaseHelper.getWrenchConfigurationByKey(migratedDb, "Integerkey")
assertTrue(cursor.moveToFirst())
- assertEquals(Bolt.TYPE.INTEGER, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
+ assertEquals(Toggle.TYPE.INTEGER, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
cursor.close()
cursor = DatabaseHelper.getWrenchConfigurationByKey(migratedDb, "Stringkey")
assertTrue(cursor.moveToFirst())
- assertEquals(Bolt.TYPE.STRING, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
+ assertEquals(Toggle.TYPE.STRING, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
cursor.close()
cursor = DatabaseHelper.getWrenchConfigurationByKey(migratedDb, "Booleankey")
assertTrue(cursor.moveToFirst())
- assertEquals(Bolt.TYPE.BOOLEAN, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
+ assertEquals(Toggle.TYPE.BOOLEAN, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
cursor.close()
cursor = DatabaseHelper.getWrenchConfigurationByKey(migratedDb, "Enumkey")
assertTrue(cursor.moveToFirst())
- assertEquals(Bolt.TYPE.ENUM, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
+ assertEquals(Toggle.TYPE.ENUM, cursor.getString(cursor.getColumnIndex(ConfigurationTable.COL_TYPE)))
cursor.close()
}
diff --git a/toggles-app/src/test/java/se/eelde/toggles/provider/TogglesProviderTest.kt b/toggles-app/src/test/java/se/eelde/toggles/provider/TogglesProviderTest.kt
index 8d51183b..dc805e19 100644
--- a/toggles-app/src/test/java/se/eelde/toggles/provider/TogglesProviderTest.kt
+++ b/toggles-app/src/test/java/se/eelde/toggles/provider/TogglesProviderTest.kt
@@ -11,10 +11,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.work.Configuration
import androidx.work.testing.SynchronousExecutor
import androidx.work.testing.WorkManagerTestInitHelper
-import com.izettle.wrench.core.Bolt
-import com.izettle.wrench.core.Nut
import com.izettle.wrench.database.WrenchDatabase
-import com.izettle.wrench.di.DatabaseModule
+import se.eelde.toggles.di.DatabaseModule
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -34,6 +32,8 @@ import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
import se.eelde.toggles.BuildConfig
import se.eelde.toggles.R
+import se.eelde.toggles.core.Toggle
+import se.eelde.toggles.core.ToggleValue
import se.eelde.toggles.core.TogglesProviderContract
import javax.inject.Singleton
@@ -83,16 +83,16 @@ class TogglesProviderTest {
}
@Test
- fun testInsertBolt() {
- val insertBoltKey = "insertBoltKey"
+ fun testInsertToggle() {
+ val insertToggleKey = "insertToggleKey"
- val uri = TogglesProviderContract.boltUri()
- val insertBolt = getBolt(insertBoltKey)
- val insertBoltUri = togglesProvider.insert(uri, insertBolt.toContentValues())
- Assert.assertNotNull(insertBoltUri)
+ val uri = TogglesProviderContract.toggleUri()
+ val insertToggle = getToggle(insertToggleKey)
+ val insertToggleUri = togglesProvider.insert(uri, insertToggle.toContentValues())
+ Assert.assertNotNull(insertToggleUri)
var cursor = togglesProvider.query(
- TogglesProviderContract.boltUri(insertBoltKey),
+ TogglesProviderContract.toggleUri(insertToggleKey),
null,
null,
null,
@@ -102,38 +102,38 @@ class TogglesProviderTest {
Assert.assertEquals(1, cursor.count)
cursor.moveToFirst()
- var queryBolt = Bolt.fromCursor(cursor)
+ var queryToggle = Toggle.fromCursor(cursor)
- Assert.assertEquals(insertBolt.key, queryBolt.key)
- Assert.assertEquals(insertBolt.value, queryBolt.value)
- Assert.assertEquals(insertBolt.type, queryBolt.type)
+ Assert.assertEquals(insertToggle.key, queryToggle.key)
+ Assert.assertEquals(insertToggle.value, queryToggle.value)
+ Assert.assertEquals(insertToggle.type, queryToggle.type)
- val boltUri = TogglesProviderContract.boltUri(
- Integer.parseInt(insertBoltUri.lastPathSegment!!).toLong()
+ val toggleUri = TogglesProviderContract.toggleUri(
+ Integer.parseInt(insertToggleUri.lastPathSegment!!).toLong()
)
- cursor = togglesProvider.query(boltUri, null, null, null, null)
+ cursor = togglesProvider.query(toggleUri, null, null, null, null)
Assert.assertNotNull(cursor)
Assert.assertEquals(1, cursor.count)
cursor.moveToFirst()
- queryBolt = Bolt.fromCursor(cursor)
+ queryToggle = Toggle.fromCursor(cursor)
- Assert.assertEquals(insertBolt.key, queryBolt.key)
- Assert.assertEquals(insertBolt.value, queryBolt.value)
- Assert.assertEquals(insertBolt.type, queryBolt.type)
+ Assert.assertEquals(insertToggle.key, queryToggle.key)
+ Assert.assertEquals(insertToggle.value, queryToggle.value)
+ Assert.assertEquals(insertToggle.type, queryToggle.type)
}
@Test
- fun testUpdateBolt() {
- val updateBoltKey = "updateBoltKey"
+ fun testUpdateToggle() {
+ val updateToggleKey = "updateToggleKey"
- val uri = TogglesProviderContract.boltUri()
- val insertBolt = getBolt(updateBoltKey)
- val insertBoltUri = togglesProvider.insert(uri, insertBolt.toContentValues())
- Assert.assertNotNull(insertBoltUri)
+ val uri = TogglesProviderContract.toggleUri()
+ val insertToggle = getToggle(updateToggleKey)
+ val insertToggleUri = togglesProvider.insert(uri, insertToggle.toContentValues())
+ Assert.assertNotNull(insertToggleUri)
var cursor = togglesProvider.query(
- TogglesProviderContract.boltUri(updateBoltKey),
+ TogglesProviderContract.toggleUri(updateToggleKey),
null,
null,
null,
@@ -142,28 +142,28 @@ class TogglesProviderTest {
Assert.assertNotNull(cursor)
Assert.assertTrue(cursor.moveToFirst())
- val providerBolt = Bolt.fromCursor(cursor)
- Assert.assertEquals(insertBolt.key, providerBolt.key)
- Assert.assertEquals(insertBolt.value, providerBolt.value)
- Assert.assertEquals(insertBolt.type, providerBolt.type)
+ val providerToggle = Toggle.fromCursor(cursor)
+ Assert.assertEquals(insertToggle.key, providerToggle.key)
+ Assert.assertEquals(insertToggle.value, providerToggle.value)
+ Assert.assertEquals(insertToggle.type, providerToggle.type)
- val updateBolt = Bolt(
- providerBolt.id,
- providerBolt.type,
- providerBolt.key,
- providerBolt.value!! + providerBolt.value!!
+ val updateToggle = Toggle(
+ providerToggle.id,
+ providerToggle.type,
+ providerToggle.key,
+ providerToggle.value!! + providerToggle.value!!
)
val update = togglesProvider.update(
- TogglesProviderContract.boltUri(updateBolt.id),
- updateBolt.toContentValues(),
+ TogglesProviderContract.toggleUri(updateToggle.id),
+ updateToggle.toContentValues(),
null,
null
)
Assert.assertEquals(1, update)
cursor = togglesProvider.query(
- TogglesProviderContract.boltUri(updateBoltKey),
+ TogglesProviderContract.toggleUri(updateToggleKey),
null,
null,
null,
@@ -172,102 +172,102 @@ class TogglesProviderTest {
Assert.assertNotNull(cursor)
Assert.assertTrue(cursor.moveToFirst())
- val updatedBolt = Bolt.fromCursor(cursor)
+ val updatedToggle = Toggle.fromCursor(cursor)
- Assert.assertEquals(insertBolt.value!! + insertBolt.value!!, updatedBolt.value)
+ Assert.assertEquals(insertToggle.value!! + insertToggle.value!!, updatedToggle.value)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingInsertForBoltWithId() {
+ fun testMissingInsertForToggleWithId() {
togglesProvider.insert(
- TogglesProviderContract.boltUri(0),
- getBolt("dummyBolt").toContentValues()
+ TogglesProviderContract.toggleUri(0),
+ getToggle("dummyToggle").toContentValues()
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingInsertForBoltWithKey() {
+ fun testMissingInsertForToggleWithKey() {
togglesProvider.insert(
- TogglesProviderContract.boltUri("fake"),
- getBolt("dummyBolt").toContentValues()
+ TogglesProviderContract.toggleUri("fake"),
+ getToggle("dummyToggle").toContentValues()
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingUpdateForBoltWithKey() {
+ fun testMissingUpdateForToggleWithKey() {
togglesProvider.update(
- TogglesProviderContract.boltUri("fake"),
- getBolt("dummyBolt").toContentValues(),
+ TogglesProviderContract.toggleUri("fake"),
+ getToggle("dummyToggle").toContentValues(),
null,
null
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingUpdateForBolts() {
+ fun testMissingUpdateForToggles() {
togglesProvider.update(
- TogglesProviderContract.boltUri(),
- getBolt("dummyBolt").toContentValues(),
+ TogglesProviderContract.toggleUri(),
+ getToggle("dummyToggle").toContentValues(),
null,
null
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingUpdateForNuts() {
+ fun testMissingUpdateForToggleValues() {
togglesProvider.update(
- TogglesProviderContract.nutUri(),
- getNut("dummyNut").toContentValues(),
+ TogglesProviderContract.toggleValueUri(),
+ getToggleValue("dummyToggleValue").toContentValues(),
null,
null
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingQueryForBolts() {
+ fun testMissingQueryForToggles() {
togglesProvider.update(
- TogglesProviderContract.boltUri(),
- getBolt("dummyBolt").toContentValues(),
+ TogglesProviderContract.toggleUri(),
+ getToggle("dummyToggle").toContentValues(),
null,
null
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingQueryForNuts() {
+ fun testMissingQueryForToggleValues() {
togglesProvider.update(
- TogglesProviderContract.nutUri(),
- getNut("dummyNut").toContentValues(),
+ TogglesProviderContract.toggleValueUri(),
+ getToggleValue("dummyToggleValue").toContentValues(),
null,
null
)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingDeleteForBoltWithId() {
- togglesProvider.delete(TogglesProviderContract.boltUri(0), null, null)
+ fun testMissingDeleteForToggleWithId() {
+ togglesProvider.delete(TogglesProviderContract.toggleUri(0), null, null)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingDeleteForBoltWithKey() {
- togglesProvider.delete(TogglesProviderContract.boltUri("fake"), null, null)
+ fun testMissingDeleteForToggleWithKey() {
+ togglesProvider.delete(TogglesProviderContract.toggleUri("fake"), null, null)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingDeleteForBolts() {
- togglesProvider.delete(TogglesProviderContract.boltUri(), null, null)
+ fun testMissingDeleteForToggles() {
+ togglesProvider.delete(TogglesProviderContract.toggleUri(), null, null)
}
@Test(expected = UnsupportedOperationException::class)
- fun testMissingDeleteForNuts() {
- togglesProvider.delete(TogglesProviderContract.nutUri(), null, null)
+ fun testMissingDeleteForToggleValues() {
+ togglesProvider.delete(TogglesProviderContract.toggleValueUri(), null, null)
}
- private fun getNut(value: String): Nut {
- return Nut(0, value)
+ private fun getToggleValue(value: String): ToggleValue {
+ return ToggleValue(0, value)
}
- private fun getBolt(key: String): Bolt {
- return Bolt(0L, "bolttype", key, "boltvalue")
+ private fun getToggle(key: String): Toggle {
+ return Toggle(0L, "toggletype", key, "togglevalue")
}
}
diff --git a/toggles-core/build.gradle.kts b/toggles-core/build.gradle.kts
index 6febb963..7fc55550 100644
--- a/toggles-core/build.gradle.kts
+++ b/toggles-core/build.gradle.kts
@@ -1,22 +1,15 @@
plugins {
id("com.android.library")
kotlin("android")
- id("io.gitlab.arturbosch.detekt")
}
-dependencies {
- detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
-}
-
-detekt {
- autoCorrect = true
-}
+apply(plugin = "com.vanniktech.maven.publish")
android {
compileSdk = 30
defaultConfig {
- minSdk = 16
+ minSdk = 21
targetSdk = 30
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -45,7 +38,7 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android.txt"))
}
}
- lintOptions {
+ lint {
baselineFile = file("lint-baseline.xml")
isCheckReleaseBuilds = true
isAbortOnError = true
@@ -63,8 +56,6 @@ android {
dependencies {
implementation("androidx.core:core-ktx:1.3.2")
- testImplementation("junit:junit:4.13.1")
- implementation("androidx.annotation:annotation:1.2.0-alpha01")
+ testImplementation("junit:junit:4.13.2")
+ implementation("androidx.annotation:annotation:1.1.0")
}
-
-apply(rootProject.file("gradle/gradle-mvn-push.gradle"))
diff --git a/toggles-core/gradle.properties b/toggles-core/gradle.properties
index d56d05a8..79b1c4ec 100644
--- a/toggles-core/gradle.properties
+++ b/toggles-core/gradle.properties
@@ -1,3 +1,3 @@
-POM_ARTIFACT_ID=wrench-core
-POM_NAME=Wrench Core
-POM_PACKAGING=aar
\ No newline at end of file
+POM_ARTIFACT_ID=toggles-core
+POM_NAME=Toggles Core
+VERSION_NAME=0.0.1
diff --git a/toggles-core/src/main/java/se/eelde/toggles/core/DownloadNotification.kt b/toggles-core/src/main/java/se/eelde/toggles/core/DownloadNotification.kt
index fadc7e9a..16469362 100644
--- a/toggles-core/src/main/java/se/eelde/toggles/core/DownloadNotification.kt
+++ b/toggles-core/src/main/java/se/eelde/toggles/core/DownloadNotification.kt
@@ -1,5 +1,6 @@
package se.eelde.toggles.core
+import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
@@ -7,17 +8,17 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
+import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
private const val CHANNEL_ID = "Download toggles channel"
private fun createNotificationChannel(context: Context) {
- // Create the NotificationChannel, but only on API 26+ because
- // the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = context.getString(R.string.download_toggles_notification_channel)
- val descriptionText = context.getString(R.string.download_toggles_notification_channel_description)
+ val descriptionText =
+ context.getString(R.string.download_toggles_notification_channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
@@ -29,6 +30,21 @@ private fun createNotificationChannel(context: Context) {
}
}
+@RequiresApi(Build.VERSION_CODES.M)
+fun getStartActivityPendingIntentPostM(context: Context, intent: Intent): PendingIntent =
+ PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+
+@SuppressLint("UnspecifiedImmutableFlag")
+fun getStartActivityPendingIntentPreM(context: Context, intent: Intent): PendingIntent =
+ PendingIntent.getActivity(context, 0, intent, 0)
+
+fun getStartActivityPendingIntent(context: Context, intent: Intent): PendingIntent =
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ getStartActivityPendingIntentPostM(context, intent)
+ } else {
+ getStartActivityPendingIntentPreM(context, intent)
+ }
+
fun showDownloadNotification(context: Context) {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(
@@ -36,15 +52,15 @@ fun showDownloadNotification(context: Context) {
)
setPackage("com.android.vending")
}
- val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
createNotificationChannel(context)
+
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download_notification)
.setContentTitle(context.getString(R.string.notification_content_title))
.setContentText(context.getString(R.string.notification_content_text))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
- .setContentIntent(pendingIntent)
+ .setContentIntent(getStartActivityPendingIntent(context, intent))
.setAutoCancel(true)
with(NotificationManagerCompat.from(context)) {
diff --git a/toggles-core/src/main/java/se/eelde/toggles/core/TogglesProviderContract.kt b/toggles-core/src/main/java/se/eelde/toggles/core/TogglesProviderContract.kt
index 3b8664d7..8254cafe 100644
--- a/toggles-core/src/main/java/se/eelde/toggles/core/TogglesProviderContract.kt
+++ b/toggles-core/src/main/java/se/eelde/toggles/core/TogglesProviderContract.kt
@@ -4,23 +4,25 @@ import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import androidx.annotation.StringDef
+import androidx.core.database.getLongOrNull
+import androidx.core.database.getStringOrNull
class ColumnNames {
- object Bolt {
+ object Toggle {
const val COL_KEY = "configurationKey"
const val COL_ID = "id"
const val COL_VALUE = "value"
const val COL_TYPE = "configurationType"
}
- object Nut {
+ object ToggleValue {
const val COL_ID = "id"
const val COL_VALUE = "value"
const val COL_CONFIG_ID = "configurationId"
}
}
-data class Nut(
+data class ToggleValue(
val id: Long = 0,
val configurationId: Long = 0,
val value: String? = null
@@ -31,18 +33,18 @@ data class Nut(
fun toContentValues(): ContentValues {
val contentValues = ContentValues()
if (id > 0) {
- contentValues.put(ColumnNames.Nut.COL_ID, id)
+ contentValues.put(ColumnNames.ToggleValue.COL_ID, id)
}
- contentValues.put(ColumnNames.Nut.COL_CONFIG_ID, configurationId)
- contentValues.put(ColumnNames.Nut.COL_VALUE, value)
+ contentValues.put(ColumnNames.ToggleValue.COL_CONFIG_ID, configurationId)
+ contentValues.put(ColumnNames.ToggleValue.COL_VALUE, value)
return contentValues
}
}
-data class Bolt(
+data class Toggle(
var id: Long = 0,
- @BoltType val type: String,
+ @ToggleType val type: String,
val key: String = "",
val value: String? = null
) {
@@ -50,17 +52,17 @@ data class Bolt(
fun toContentValues(): ContentValues {
val contentValues = ContentValues()
- contentValues.put(ColumnNames.Bolt.COL_ID, id)
- contentValues.put(ColumnNames.Bolt.COL_KEY, key)
- contentValues.put(ColumnNames.Bolt.COL_VALUE, value)
- contentValues.put(ColumnNames.Bolt.COL_TYPE, type)
+ contentValues.put(ColumnNames.Toggle.COL_ID, id)
+ contentValues.put(ColumnNames.Toggle.COL_KEY, key)
+ contentValues.put(ColumnNames.Toggle.COL_VALUE, value)
+ contentValues.put(ColumnNames.Toggle.COL_TYPE, type)
return contentValues
}
@StringDef(TYPE.BOOLEAN, TYPE.STRING, TYPE.INTEGER, TYPE.ENUM)
@Retention(AnnotationRetention.SOURCE)
- annotation class BoltType
+ annotation class ToggleType
object TYPE {
const val BOOLEAN = "boolean"
@@ -70,55 +72,39 @@ data class Bolt(
}
companion object {
-
@JvmStatic
- fun fromContentValues(values: ContentValues): Bolt {
-
- return Bolt(
- id = values.getAsLong(ColumnNames.Bolt.COL_ID) ?: 0,
- type = values.getAsString(ColumnNames.Bolt.COL_TYPE),
- key = values.getAsString(ColumnNames.Bolt.COL_KEY),
- value = values.getAsString(ColumnNames.Bolt.COL_VALUE)
+ fun fromContentValues(values: ContentValues): Toggle {
+ return Toggle(
+ id = values.getAsLong(ColumnNames.Toggle.COL_ID) ?: 0,
+ type = values.getAsString(ColumnNames.Toggle.COL_TYPE),
+ key = values.getAsString(ColumnNames.Toggle.COL_KEY),
+ value = values.getAsString(ColumnNames.Toggle.COL_VALUE)
)
}
@JvmStatic
- fun fromCursor(cursor: Cursor): Bolt {
- return Bolt(
- id = cursor.getLongOrThrow(ColumnNames.Bolt.COL_ID),
- type = cursor.getStringOrThrow(ColumnNames.Bolt.COL_TYPE),
- key = cursor.getStringOrThrow(ColumnNames.Bolt.COL_KEY),
- value = cursor.getStringOrNull(ColumnNames.Bolt.COL_VALUE)
+ fun fromCursor(cursor: Cursor): Toggle {
+ return Toggle(
+ id = cursor.getLongOrNull(cursor.getColumnIndexOrThrow(ColumnNames.Toggle.COL_ID))!!,
+ type = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(ColumnNames.Toggle.COL_TYPE))!!,
+ key = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(ColumnNames.Toggle.COL_KEY))!!,
+ value = cursor.getStringOrNull(cursor.getColumnIndexOrThrow(ColumnNames.Toggle.COL_VALUE))
)
}
}
}
-private fun Cursor.getStringOrThrow(columnName: String): String = getStringOrNull(columnName)!!
-
-private fun Cursor.getStringOrNull(columnName: String): String? {
- val index = getColumnIndexOrThrow(columnName)
- return if (isNull(index)) null else getString(index)
-}
-
-private fun Cursor.getLongOrThrow(columnName: String): Long = getLongOrNull(columnName)!!
-
-private fun Cursor.getLongOrNull(columnName: String): Long? {
- val index = getColumnIndexOrThrow(columnName)
- return if (isNull(index)) null else getLong(index)
-}
-
object TogglesProviderContract {
const val TOGGLES_AUTHORITY = BuildConfig.TOGGLES_AUTHORITY
const val TOGGLES_API_VERSION = "API_VERSION"
private val applicationUri = Uri.parse("content://$TOGGLES_AUTHORITY/application")
- private val boltUri = Uri.parse("content://$TOGGLES_AUTHORITY/currentConfiguration")
- private val nutUri = Uri.parse("content://$TOGGLES_AUTHORITY/predefinedConfigurationValue")
+ private val configurationUri = Uri.parse("content://$TOGGLES_AUTHORITY/currentConfiguration")
+ private val configurationValueUri = Uri.parse("content://$TOGGLES_AUTHORITY/predefinedConfigurationValue")
@JvmStatic
- fun applicationUri(id: Long): Uri? {
+ fun applicationUri(id: Long): Uri {
return applicationUri
.buildUpon()
.appendPath(id.toString())
@@ -127,8 +113,8 @@ object TogglesProviderContract {
}
@JvmStatic
- fun boltUri(id: Long): Uri {
- return boltUri
+ fun toggleUri(id: Long): Uri {
+ return configurationUri
.buildUpon()
.appendPath(id.toString())
.appendQueryParameter(TOGGLES_API_VERSION, BuildConfig.TOGGLES_API_VERSION.toString())
@@ -136,8 +122,8 @@ object TogglesProviderContract {
}
@JvmStatic
- fun boltUri(key: String): Uri {
- return boltUri
+ fun toggleUri(key: String): Uri {
+ return configurationUri
.buildUpon()
.appendPath(key)
.appendQueryParameter(TOGGLES_API_VERSION, BuildConfig.TOGGLES_API_VERSION.toString())
@@ -145,16 +131,16 @@ object TogglesProviderContract {
}
@JvmStatic
- fun boltUri(): Uri {
- return boltUri
+ fun toggleUri(): Uri {
+ return configurationUri
.buildUpon()
.appendQueryParameter(TOGGLES_API_VERSION, BuildConfig.TOGGLES_API_VERSION.toString())
.build()
}
@JvmStatic
- fun nutUri(): Uri {
- return nutUri
+ fun toggleValueUri(): Uri {
+ return configurationValueUri
.buildUpon()
.appendQueryParameter(TOGGLES_API_VERSION, BuildConfig.TOGGLES_API_VERSION.toString())
.build()
diff --git a/toggles-core/src/test/java/com/izettle/wrench/core/ExampleUnitTest.java b/toggles-core/src/test/java/com/izettle/wrench/core/ExampleUnitTest.java
deleted file mode 100644
index af61c4c0..00000000
--- a/toggles-core/src/test/java/com/izettle/wrench/core/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.izettle.wrench.core;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * 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);
- }
-}
\ No newline at end of file
diff --git a/toggles-coroutines/src/test/java/se/eelde/toggles/coroutines/ExampleUnitTest.kt b/toggles-core/src/test/java/com/izettle/wrench/core/ExampleUnitTest.kt
similarity index 90%
rename from toggles-coroutines/src/test/java/se/eelde/toggles/coroutines/ExampleUnitTest.kt
rename to toggles-core/src/test/java/com/izettle/wrench/core/ExampleUnitTest.kt
index 057a3d1b..1208c407 100644
--- a/toggles-coroutines/src/test/java/se/eelde/toggles/coroutines/ExampleUnitTest.kt
+++ b/toggles-core/src/test/java/com/izettle/wrench/core/ExampleUnitTest.kt
@@ -1,4 +1,4 @@
-package se.eelde.toggles.coroutines
+package com.izettle.wrench.core
import org.junit.Assert.assertEquals
import org.junit.Test
diff --git a/toggles-coroutines/src/main/java/se/eelde/toggles/coroutines/TogglesCoroutines.kt b/toggles-coroutines/src/main/java/se/eelde/toggles/coroutines/TogglesCoroutines.kt
deleted file mode 100644
index 9554a9a6..00000000
--- a/toggles-coroutines/src/main/java/se/eelde/toggles/coroutines/TogglesCoroutines.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-package se.eelde.toggles.coroutines
-
-import android.content.ContentResolver
-import android.content.Context
-import android.database.ContentObserver
-import android.database.Cursor
-import android.net.Uri
-import android.os.Handler
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import se.eelde.toggles.core.Bolt
-import se.eelde.toggles.core.Bolt.BoltType
-import se.eelde.toggles.core.Bolt.Companion.fromCursor
-import se.eelde.toggles.core.Nut
-import se.eelde.toggles.core.TogglesProviderContract
-import se.eelde.toggles.core.TogglesProviderContract.boltUri
-import se.eelde.toggles.core.showDownloadNotification
-
-@ExperimentalCoroutinesApi
-fun booleanBoltFlow(context: Context, key: String, defaultValue: Boolean = true): Flow =
- boltFlow(context, Bolt.TYPE.BOOLEAN, key)
- .map { bolt ->
- when {
- bolt == null -> defaultValue
- bolt.id == 0L -> {
- context.contentResolver.insert(boltUri(), bolt.copy(bolt.id, bolt.type, key, defaultValue.toString()).toContentValues())
- defaultValue
- }
- bolt.value == null -> defaultValue
- else -> bolt.value.toBoolean()
- }
- }
-
-@ExperimentalCoroutinesApi
-fun stringBoltFlow(context: Context, key: String, defaultValue: String = ""): Flow =
- boltFlow(context, Bolt.TYPE.STRING, key)
- .map { bolt ->
- when {
- bolt == null -> defaultValue
- bolt.id == 0L -> {
- context.contentResolver.insert(boltUri(), bolt.copy(bolt.id, bolt.type, key, defaultValue).toContentValues())
- defaultValue
- }
- bolt.value == null -> defaultValue
- else -> bolt.value!!
- }
- }
-
-@ExperimentalCoroutinesApi
-fun integerBoltFlow(context: Context, key: String, defaultValue: Int = 0): Flow =
- boltFlow(context, Bolt.TYPE.INTEGER, key)
- .map { bolt ->
- when {
- bolt == null -> defaultValue
- bolt.id == 0L -> {
- context.contentResolver.insert(boltUri(), bolt.copy(bolt.id, bolt.type, key, defaultValue.toString()).toContentValues())
- defaultValue
- }
- bolt.value == null -> defaultValue
- else -> bolt.value!!.toInt()
- }
- }
-
-@ExperimentalCoroutinesApi
-fun > enumBoltFlow(context: Context, key: String, type: Class, defaultValue: T): Flow =
- boltFlow(context, Bolt.TYPE.ENUM, key)
- .map { bolt ->
- when {
- bolt == null -> defaultValue
- bolt.id == 0L -> {
- val uri = context.contentResolver.insert(boltUri(), bolt.copy(bolt.id, bolt.type, key, defaultValue.toString()).toContentValues())
- val configurationId = uri!!.lastPathSegment!!.toLong()
-
- for (enumConstant in type.enumConstants!!) {
- val nut = Nut(configurationId = configurationId, value = enumConstant.toString())
- context.contentResolver.insert(TogglesProviderContract.nutUri(), nut.toContentValues())
- }
- defaultValue
- }
- bolt.value == null -> defaultValue
- else -> java.lang.Enum.valueOf(type, bolt.value!!)
- }
- }
-
-@ExperimentalCoroutinesApi
-fun boltFlow(context: Context, @BoltType type: String, key: String): Flow = callbackFlow {
-
- val boltContentObserver = BoltContentObserver(null) {
- launch {
- offer(getBolt(context.contentResolver, type, key))
- }
- }
-
- val providerInfo = context.packageManager.resolveContentProvider(TogglesProviderContract.TOGGLES_AUTHORITY, 0)
- if (providerInfo != null) {
- context.contentResolver
- .registerContentObserver(boltUri(), true, boltContentObserver)
- } else {
- showDownloadNotification(context = context)
- }
-
- offer(getBolt(context.contentResolver, type, key))
-
- awaitClose {
- context.contentResolver.unregisterContentObserver(boltContentObserver)
- }
-}
-
-private suspend fun getBolt(contentResolver: ContentResolver, @BoltType type: String, key: String): Bolt? = withContext(Dispatchers.IO) {
- var cursor: Cursor? = null
- try {
- cursor = contentResolver.query(
- boltUri(key),
- null,
- null,
- null,
- null
- )
- if (cursor == null) {
- return@withContext null
- }
- if (cursor.moveToFirst()) {
- return@withContext fromCursor(cursor)
- }
- } finally {
- if (cursor != null && !cursor.isClosed) {
- cursor.close()
- }
- }
- return@withContext Bolt(0L, type, key, "")
-}
-
-class BoltContentObserver(handler: Handler?, private val changeCallback: (uri: Uri?) -> Unit) : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean) {
- this.onChange(selfChange, null)
- }
-
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- changeCallback.invoke(uri)
- }
-}
diff --git a/toggles-coroutines/.gitignore b/toggles-flow/.gitignore
similarity index 100%
rename from toggles-coroutines/.gitignore
rename to toggles-flow/.gitignore
diff --git a/toggles-coroutines/build.gradle.kts b/toggles-flow/build.gradle.kts
similarity index 66%
rename from toggles-coroutines/build.gradle.kts
rename to toggles-flow/build.gradle.kts
index be9f9a46..9650ea54 100644
--- a/toggles-coroutines/build.gradle.kts
+++ b/toggles-flow/build.gradle.kts
@@ -1,22 +1,15 @@
plugins {
id("com.android.library")
kotlin("android")
- id("io.gitlab.arturbosch.detekt")
}
-dependencies {
- detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
-}
-
-detekt {
- autoCorrect = true
-}
+apply(plugin = "com.vanniktech.maven.publish")
android {
compileSdk = 30
defaultConfig {
- minSdk = 16
+ minSdk = 21
targetSdk = 30
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -27,7 +20,7 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android.txt"))
}
}
- lintOptions {
+ lint {
baselineFile = file("lint-baseline.xml")
isCheckReleaseBuilds = true
isAbortOnError = true
@@ -39,6 +32,9 @@ android {
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
+ freeCompilerArgs = listOfNotNull(
+ "-Xopt-in=kotlin.RequiresOptIn"
+ )
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -47,21 +43,17 @@ android {
}
dependencies {
- testImplementation("junit:junit:4.13.1")
+ testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test:core:1.3.0")
testImplementation("androidx.test.ext:truth:1.3.0")
testImplementation("androidx.test:rules:1.3.0")
testImplementation("androidx.test:runner:1.3.0")
testImplementation("androidx.test.ext:junit:1.1.2")
- testImplementation("org.robolectric:robolectric:4.4")
+ testImplementation("org.robolectric:robolectric:4.5.1")
implementation(project(":toggles-core"))
- implementation("androidx.annotation:annotation:1.2.0-alpha01")
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21")
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2")
- implementation("androidx.core:core-ktx:1.5.0-alpha05")
+ implementation("androidx.annotation:annotation:1.1.0")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3")
+ implementation("androidx.core:core-ktx:1.3.2")
}
-
-// The api of this module should be discussed before any potential release
-// apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
diff --git a/toggles-coroutines/consumer-rules.pro b/toggles-flow/consumer-rules.pro
similarity index 100%
rename from toggles-coroutines/consumer-rules.pro
rename to toggles-flow/consumer-rules.pro
diff --git a/toggles-flow/gradle.properties b/toggles-flow/gradle.properties
new file mode 100644
index 00000000..078a7049
--- /dev/null
+++ b/toggles-flow/gradle.properties
@@ -0,0 +1,3 @@
+POM_ARTIFACT_ID=toggles-flow
+POM_NAME=Toggles Flow
+VERSION_NAME=0.0.1-SNAPSHOT
diff --git a/toggles-coroutines/lint-baseline.xml b/toggles-flow/lint-baseline.xml
similarity index 100%
rename from toggles-coroutines/lint-baseline.xml
rename to toggles-flow/lint-baseline.xml
diff --git a/toggles-coroutines/proguard-rules.pro b/toggles-flow/proguard-rules.pro
similarity index 100%
rename from toggles-coroutines/proguard-rules.pro
rename to toggles-flow/proguard-rules.pro
diff --git a/toggles-coroutines/src/main/AndroidManifest.xml b/toggles-flow/src/main/AndroidManifest.xml
similarity index 91%
rename from toggles-coroutines/src/main/AndroidManifest.xml
rename to toggles-flow/src/main/AndroidManifest.xml
index bf996bb6..8bb27a90 100644
--- a/toggles-coroutines/src/main/AndroidManifest.xml
+++ b/toggles-flow/src/main/AndroidManifest.xml
@@ -1,7 +1,7 @@
+ package="se.eelde.toggles.flow">
diff --git a/toggles-flow/src/main/java/se/eelde/toggles/flow/ToggleFlow.kt b/toggles-flow/src/main/java/se/eelde/toggles/flow/ToggleFlow.kt
new file mode 100644
index 00000000..efbb0c4f
--- /dev/null
+++ b/toggles-flow/src/main/java/se/eelde/toggles/flow/ToggleFlow.kt
@@ -0,0 +1,195 @@
+package se.eelde.toggles.flow
+
+import android.content.ContentResolver
+import android.content.Context
+import android.database.ContentObserver
+import android.database.Cursor
+import android.net.Uri
+import android.os.Handler
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import se.eelde.toggles.core.Toggle
+import se.eelde.toggles.core.Toggle.ToggleType
+import se.eelde.toggles.core.Toggle.Companion.fromCursor
+import se.eelde.toggles.core.ToggleValue
+import se.eelde.toggles.core.TogglesProviderContract
+import se.eelde.toggles.core.TogglesProviderContract.toggleUri
+import se.eelde.toggles.core.showDownloadNotification
+
+@ExperimentalCoroutinesApi
+fun toggleFlow(context: Context, key: String, defaultValue: Boolean = true): Flow =
+ providerToggleFlow(context, Toggle.TYPE.BOOLEAN, key)
+ .map { toggle ->
+ when {
+ toggle == null -> defaultValue
+ toggle.id == 0L -> {
+ context.contentResolver.insert(
+ toggleUri(),
+ toggle.copy(
+ id = toggle.id,
+ type = toggle.type,
+ key = key,
+ value = defaultValue.toString()
+ ).toContentValues()
+ )
+ defaultValue
+ }
+ toggle.value == null -> defaultValue
+ else -> toggle.value!!.toBoolean()
+ }
+ }
+
+@ExperimentalCoroutinesApi
+fun toggleFlow(context: Context, key: String, defaultValue: String = ""): Flow =
+ providerToggleFlow(context, Toggle.TYPE.STRING, key)
+ .map { toggle ->
+ when {
+ toggle == null -> defaultValue
+ toggle.id == 0L -> {
+ context.contentResolver.insert(
+ toggleUri(),
+ toggle.copy(
+ id = toggle.id,
+ type = toggle.type,
+ key = key,
+ value = defaultValue
+ ).toContentValues()
+ )
+ defaultValue
+ }
+ toggle.value == null -> defaultValue
+ else -> toggle.value!!
+ }
+ }
+
+@ExperimentalCoroutinesApi
+fun toggleFlow(context: Context, key: String, defaultValue: Int = 0): Flow =
+ providerToggleFlow(context, Toggle.TYPE.INTEGER, key)
+ .map { toggle ->
+ when {
+ toggle == null -> defaultValue
+ toggle.id == 0L -> {
+ context.contentResolver.insert(
+ toggleUri(),
+ toggle.copy(
+ id = toggle.id,
+ type = toggle.type,
+ key = key,
+ value = defaultValue.toString()
+ ).toContentValues()
+ )
+ defaultValue
+ }
+ toggle.value == null -> defaultValue
+ else -> toggle.value!!.toInt()
+ }
+ }
+
+@ExperimentalCoroutinesApi
+fun > toggleFlow(
+ context: Context,
+ key: String,
+ type: Class,
+ defaultValue: T
+): Flow =
+ providerToggleFlow(context, Toggle.TYPE.ENUM, key)
+ .map { toggle ->
+ when {
+ toggle == null -> defaultValue
+ toggle.id == 0L -> {
+ val uri = context.contentResolver.insert(
+ toggleUri(),
+ toggle.copy(
+ id = toggle.id,
+ type = toggle.type,
+ key = key,
+ value = defaultValue.toString()
+ ).toContentValues()
+ )
+ val configurationId = uri!!.lastPathSegment!!.toLong()
+
+ for (enumConstant in type.enumConstants!!) {
+ val toggleValue =
+ ToggleValue(configurationId = configurationId, value = enumConstant.toString())
+ context.contentResolver.insert(
+ TogglesProviderContract.toggleValueUri(),
+ toggleValue.toContentValues()
+ )
+ }
+ defaultValue
+ }
+ toggle.value == null -> defaultValue
+ else -> java.lang.Enum.valueOf(type, toggle.value!!)
+ }
+ }
+
+@ExperimentalCoroutinesApi
+private fun providerToggleFlow(context: Context, @ToggleType type: String, key: String): Flow = callbackFlow {
+
+ val toggleContentObserver = ToggleContentObserver(null) {
+ launch {
+ offer(getToggle(context.contentResolver, type, key))
+ }
+ }
+
+ val providerInfo =
+ context.packageManager.resolveContentProvider(TogglesProviderContract.TOGGLES_AUTHORITY, 0)
+ if (providerInfo != null) {
+ context.contentResolver
+ .registerContentObserver(toggleUri(), true, toggleContentObserver)
+ } else {
+ showDownloadNotification(context = context)
+ }
+
+ offer(getToggle(context.contentResolver, type, key))
+
+ awaitClose {
+ context.contentResolver.unregisterContentObserver(toggleContentObserver)
+ }
+}
+
+private suspend fun getToggle(
+ contentResolver: ContentResolver,
+ @ToggleType type: String,
+ key: String
+): Toggle? =
+ withContext(Dispatchers.IO) {
+ var cursor: Cursor? = null
+ try {
+ cursor = contentResolver.query(
+ toggleUri(key),
+ null,
+ null,
+ null,
+ null
+ )
+ if (cursor == null) {
+ return@withContext null
+ }
+ if (cursor.moveToFirst()) {
+ return@withContext fromCursor(cursor)
+ }
+ } finally {
+ if (cursor != null && !cursor.isClosed) {
+ cursor.close()
+ }
+ }
+ return@withContext Toggle(0L, type, key, "")
+ }
+
+class ToggleContentObserver(handler: Handler?, private val changeCallback: (uri: Uri?) -> Unit) :
+ ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean) {
+ this.onChange(selfChange, null)
+ }
+
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ changeCallback.invoke(uri)
+ }
+}
diff --git a/toggles-flow/src/test/java/se/eelde/toggles/flow/ExampleUnitTest.kt b/toggles-flow/src/test/java/se/eelde/toggles/flow/ExampleUnitTest.kt
new file mode 100644
index 00000000..fde73e18
--- /dev/null
+++ b/toggles-flow/src/test/java/se/eelde/toggles/flow/ExampleUnitTest.kt
@@ -0,0 +1,16 @@
+package se.eelde.toggles.flow
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/toggles-prefs/build.gradle.kts b/toggles-prefs/build.gradle.kts
index 7906837f..737325c0 100644
--- a/toggles-prefs/build.gradle.kts
+++ b/toggles-prefs/build.gradle.kts
@@ -1,22 +1,15 @@
plugins {
id("com.android.library")
kotlin("android")
- id("io.gitlab.arturbosch.detekt")
}
-dependencies {
- detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
-}
-
-detekt {
- autoCorrect = true
-}
+apply(plugin = "com.vanniktech.maven.publish")
android {
compileSdk = 30
defaultConfig {
- minSdk = 16
+ minSdk = 21
targetSdk = 30
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -27,7 +20,7 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android.txt"))
}
}
- lintOptions {
+ lint {
baselineFile = file("lint-baseline.xml")
isCheckReleaseBuilds = true
isAbortOnError = true
@@ -47,19 +40,16 @@ android {
}
dependencies {
- testImplementation("junit:junit:4.13.1")
+ testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test:core:1.3.0")
testImplementation("androidx.test.ext:truth:1.3.0")
testImplementation("androidx.test:rules:1.3.0")
testImplementation("androidx.test:runner:1.3.0")
testImplementation("androidx.test.ext:junit:1.1.2")
- testImplementation("org.robolectric:robolectric:4.4")
+ testImplementation("org.robolectric:robolectric:4.5.1")
implementation(project(":toggles-core"))
- implementation("androidx.annotation:annotation:1.2.0-alpha01")
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21")
- implementation("androidx.core:core-ktx:1.5.0-alpha05")
+ implementation("androidx.annotation:annotation:1.1.0")
+ implementation("androidx.core:core-ktx:1.3.2")
}
-
-apply(rootProject.file("gradle/gradle-mvn-push.gradle"))
diff --git a/toggles-prefs/gradle.properties b/toggles-prefs/gradle.properties
index ee295195..14c81c6c 100644
--- a/toggles-prefs/gradle.properties
+++ b/toggles-prefs/gradle.properties
@@ -1,3 +1,3 @@
-POM_ARTIFACT_ID=wrench-prefs
-POM_NAME=Wrench Prefs
-POM_PACKAGING=aar
\ No newline at end of file
+POM_ARTIFACT_ID=toggles-prefs
+POM_NAME=Toggles Prefs
+VERSION_NAME=0.0.1-SNAPSHOT
diff --git a/toggles-prefs/src/main/java/com/izettle/wrench/preferences/TogglesPreferences.kt b/toggles-prefs/src/main/java/com/izettle/wrench/preferences/TogglesPreferences.kt
index 79c2c2e6..f480c224 100644
--- a/toggles-prefs/src/main/java/com/izettle/wrench/preferences/TogglesPreferences.kt
+++ b/toggles-prefs/src/main/java/com/izettle/wrench/preferences/TogglesPreferences.kt
@@ -3,8 +3,8 @@ package com.izettle.wrench.preferences
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
-import se.eelde.toggles.core.Bolt
-import se.eelde.toggles.core.Nut
+import se.eelde.toggles.core.Toggle
+import se.eelde.toggles.core.ToggleValue
import se.eelde.toggles.core.TogglesProviderContract
import se.eelde.toggles.core.showDownloadNotification
@@ -19,13 +19,13 @@ class TogglesPreferences(context: Context) : ITogglesPreferences {
private val context = context.applicationContext
private val contentResolver: ContentResolver = context.contentResolver
- private fun insertNut(contentResolver: ContentResolver, nut: Nut) {
- contentResolver.insert(TogglesProviderContract.nutUri(), nut.toContentValues())
+ private fun insertToggleValue(contentResolver: ContentResolver, toggleValue: ToggleValue) {
+ contentResolver.insert(TogglesProviderContract.toggleValueUri(), toggleValue.toContentValues())
}
@Suppress("ReturnCount")
- private fun getBolt(contentResolver: ContentResolver, @Bolt.BoltType boltType: String, key: String): Bolt? {
- val cursor = contentResolver.query(TogglesProviderContract.boltUri(key), null, null, null, null)
+ private fun getToggle(contentResolver: ContentResolver, @Toggle.ToggleType toggleType: String, key: String): Toggle? {
+ val cursor = contentResolver.query(TogglesProviderContract.toggleUri(key), null, null, null, null)
cursor.use {
if (cursor == null) {
showDownloadNotification(context = context)
@@ -33,68 +33,68 @@ class TogglesPreferences(context: Context) : ITogglesPreferences {
}
if (cursor.moveToFirst()) {
- return Bolt.fromCursor(cursor)
+ return Toggle.fromCursor(cursor)
}
}
- return Bolt(0, boltType, key, null)
+ return Toggle(0, toggleType, key, null)
}
- private fun insertBolt(contentResolver: ContentResolver, bolt: Bolt): Uri? {
- return contentResolver.insert(TogglesProviderContract.boltUri(), bolt.toContentValues())
+ private fun insertToggle(contentResolver: ContentResolver, toggle: Toggle): Uri? {
+ return contentResolver.insert(TogglesProviderContract.toggleUri(), toggle.toContentValues())
}
override fun > getEnum(key: String, type: Class, defValue: T): T {
- var bolt = getBolt(contentResolver = contentResolver, boltType = Bolt.TYPE.ENUM, key = key)
+ var toggle = getToggle(contentResolver = contentResolver, toggleType = Toggle.TYPE.ENUM, key = key)
?: return defValue
- if (bolt.id == 0L) {
- bolt = bolt.copy(id = bolt.id, key = key, type = Bolt.TYPE.ENUM, value = defValue.toString())
- val uri = insertBolt(contentResolver, bolt)
- bolt.id = uri!!.lastPathSegment!!.toLong()
+ if (toggle.id == 0L) {
+ toggle = toggle.copy(id = toggle.id, key = key, type = Toggle.TYPE.ENUM, value = defValue.toString())
+ val uri = insertToggle(contentResolver, toggle)
+ toggle.id = uri!!.lastPathSegment!!.toLong()
for (enumConstant in type.enumConstants!!) {
- insertNut(contentResolver = contentResolver, nut = Nut(configurationId = bolt.id, value = enumConstant.toString()))
+ insertToggleValue(contentResolver = contentResolver, toggleValue = ToggleValue(configurationId = toggle.id, value = enumConstant.toString()))
}
}
- return java.lang.Enum.valueOf(type, bolt.value!!)
+ return java.lang.Enum.valueOf(type, toggle.value!!)
}
override fun getString(key: String, defValue: String?): String? {
- var bolt = getBolt(contentResolver = contentResolver, boltType = Bolt.TYPE.STRING, key = key)
+ var toggle = getToggle(contentResolver = contentResolver, toggleType = Toggle.TYPE.STRING, key = key)
?: return defValue
- if (bolt.id == 0L) {
- bolt = bolt.copy(id = bolt.id, key = key, type = Bolt.TYPE.STRING, value = defValue)
- insertBolt(contentResolver, bolt)
+ if (toggle.id == 0L) {
+ toggle = toggle.copy(id = toggle.id, key = key, type = Toggle.TYPE.STRING, value = defValue)
+ insertToggle(contentResolver, toggle)
}
- return bolt.value
+ return toggle.value
}
override fun getBoolean(key: String, defValue: Boolean): Boolean {
- var bolt = getBolt(contentResolver = contentResolver, boltType = Bolt.TYPE.BOOLEAN, key = key)
+ var toggle = getToggle(contentResolver = contentResolver, toggleType = Toggle.TYPE.BOOLEAN, key = key)
?: return defValue
- if (bolt.id == 0L) {
- bolt = bolt.copy(id = bolt.id, key = key, type = Bolt.TYPE.BOOLEAN, value = defValue.toString())
- insertBolt(contentResolver, bolt)
+ if (toggle.id == 0L) {
+ toggle = toggle.copy(id = toggle.id, key = key, type = Toggle.TYPE.BOOLEAN, value = defValue.toString())
+ insertToggle(contentResolver, toggle)
}
- return bolt.value!!.toBoolean()
+ return toggle.value!!.toBoolean()
}
override fun getInt(key: String, defValue: Int): Int {
- var bolt = getBolt(contentResolver = contentResolver, boltType = Bolt.TYPE.INTEGER, key = key)
+ var toggle = getToggle(contentResolver = contentResolver, toggleType = Toggle.TYPE.INTEGER, key = key)
?: return defValue
- if (bolt.id == 0L) {
- bolt = bolt.copy(id = bolt.id, key = key, type = Bolt.TYPE.INTEGER, value = defValue.toString())
- insertBolt(contentResolver, bolt)
+ if (toggle.id == 0L) {
+ toggle = toggle.copy(id = toggle.id, key = key, type = Toggle.TYPE.INTEGER, value = defValue.toString())
+ insertToggle(contentResolver, toggle)
}
- return bolt.value!!.toInt()
+ return toggle.value!!.toInt()
}
}
diff --git a/toggles-prefs/src/test/AndroidManifest.xml b/toggles-prefs/src/test/AndroidManifest.xml
new file mode 100644
index 00000000..086a29ab
--- /dev/null
+++ b/toggles-prefs/src/test/AndroidManifest.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsDefaultWhenMissingProviderTest.kt b/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsDefaultWhenMissingProviderTest.kt
index 414dedc2..cb901539 100644
--- a/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsDefaultWhenMissingProviderTest.kt
+++ b/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsDefaultWhenMissingProviderTest.kt
@@ -29,7 +29,7 @@ class WrenchPreferencesReturnsDefaultWhenMissingProviderTest {
val applicationContext = ApplicationProvider.getApplicationContext()
wrenchPreferences = TogglesPreferences(applicationContext)
- val query = applicationContext.contentResolver.query(TogglesProviderContract.boltUri(""), null, null, null, null)
+ val query = applicationContext.contentResolver.query(TogglesProviderContract.toggleUri(""), null, null, null, null)
Assert.assertNull(query)
}
diff --git a/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsProviderValues.kt b/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsProviderValues.kt
index 4be0c5cd..1551b9e9 100644
--- a/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsProviderValues.kt
+++ b/toggles-prefs/src/test/java/com/izettle/wrench/preferences/WrenchPreferencesReturnsProviderValues.kt
@@ -19,7 +19,7 @@ import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.android.controller.ContentProviderController
import org.robolectric.annotation.Config
-import se.eelde.toggles.core.Bolt
+import se.eelde.toggles.core.Toggle
import se.eelde.toggles.core.ColumnNames
import se.eelde.toggles.core.TogglesProviderContract
@@ -34,6 +34,7 @@ class WrenchPreferencesReturnsProviderValues {
FIRST, SECOND
}
+
private lateinit var contentProviderController: ContentProviderController
@Before
@@ -47,7 +48,7 @@ class WrenchPreferencesReturnsProviderValues {
@Test
fun `return provider enum when available`() {
- assertEquals(0, contentProviderController.get().bolts.size)
+ assertEquals(0, contentProviderController.get().toggles.size)
assertEquals(TestEnum.FIRST, wrenchPreferences.getEnum(key, TestEnum::class.java, TestEnum.FIRST))
assertEquals(TestEnum.FIRST, wrenchPreferences.getEnum(key, TestEnum::class.java, TestEnum.SECOND))
@@ -55,7 +56,7 @@ class WrenchPreferencesReturnsProviderValues {
@Test
fun `return provider string when available`() {
- assertEquals(0, contentProviderController.get().bolts.size)
+ assertEquals(0, contentProviderController.get().toggles.size)
assertEquals("first", wrenchPreferences.getString(key, "first"))
assertEquals("first", wrenchPreferences.getString(key, "second"))
@@ -63,7 +64,7 @@ class WrenchPreferencesReturnsProviderValues {
@Test
fun `return provider boolean when available`() {
- assertEquals(0, contentProviderController.get().bolts.size)
+ assertEquals(0, contentProviderController.get().toggles.size)
assertEquals(true, wrenchPreferences.getBoolean(key, true))
assertEquals(true, wrenchPreferences.getBoolean(key, false))
@@ -71,7 +72,7 @@ class WrenchPreferencesReturnsProviderValues {
@Test
fun `return provider int when available`() {
- assertEquals(0, contentProviderController.get().bolts.size)
+ assertEquals(0, contentProviderController.get().toggles.size)
assertEquals(1, wrenchPreferences.getInt(key, 1))
assertEquals(1, wrenchPreferences.getInt(key, 2))
@@ -95,8 +96,8 @@ class MockContentProvider : ContentProvider() {
}
}
- val bolts: MutableMap = mutableMapOf()
- private val nuts: MutableList = mutableListOf()
+ val toggles: MutableMap = mutableMapOf()
+ private val toggleValues: MutableList = mutableListOf()
override fun onCreate(): Boolean {
return true
@@ -108,17 +109,17 @@ class MockContentProvider : ContentProvider() {
selection: String?,
selectionArgs: Array?,
sortOrder: String?
- ): Cursor? {
+ ): Cursor {
when (uriMatcher.match(uri)) {
CURRENT_CONFIGURATION_ID -> {
- throw IllegalArgumentException("bolt exists")
+ throw IllegalArgumentException("toggle exists")
}
CURRENT_CONFIGURATION_KEY -> {
- val cursor = MatrixCursor(arrayOf(ColumnNames.Bolt.COL_ID, ColumnNames.Bolt.COL_KEY, ColumnNames.Bolt.COL_TYPE, ColumnNames.Bolt.COL_VALUE))
+ val cursor = MatrixCursor(arrayOf(ColumnNames.Toggle.COL_ID, ColumnNames.Toggle.COL_KEY, ColumnNames.Toggle.COL_TYPE, ColumnNames.Toggle.COL_VALUE))
uri.lastPathSegment?.let { key ->
- bolts[key]?.let { bolt ->
- cursor.addRow(arrayOf(bolt.id, bolt.key, bolt.type, bolt.value))
+ toggles[key]?.let { toggle ->
+ cursor.addRow(arrayOf(toggle.id, toggle.key, toggle.type, toggle.value))
}
}
@@ -134,17 +135,17 @@ class MockContentProvider : ContentProvider() {
val insertId: Long
when (uriMatcher.match(uri)) {
CURRENT_CONFIGURATIONS -> {
- val bolt = Bolt.fromContentValues(values!!)
- if (bolts.containsKey(bolt.key)) {
- throw IllegalArgumentException("bolt exists")
+ val toggle = Toggle.fromContentValues(values!!)
+ if (toggles.containsKey(toggle.key)) {
+ throw IllegalArgumentException("toggle exists")
}
- bolts[bolt.key] = bolt
- insertId = bolts.size.toLong()
- bolt.id = insertId
+ toggles[toggle.key] = toggle
+ insertId = toggles.size.toLong()
+ toggle.id = insertId
}
PREDEFINED_CONFIGURATION_VALUES -> {
- nuts.add(values!!.getAsString(ColumnNames.Nut.COL_VALUE))
- insertId = nuts.size.toLong()
+ toggleValues.add(values!!.getAsString(ColumnNames.ToggleValue.COL_VALUE))
+ insertId = toggleValues.size.toLong()
}
else -> {
throw UnsupportedOperationException("Not yet implemented $uri")
diff --git a/toggles-sample/build.gradle.kts b/toggles-sample/build.gradle.kts
index 695c9e66..8666fc19 100644
--- a/toggles-sample/build.gradle.kts
+++ b/toggles-sample/build.gradle.kts
@@ -5,15 +5,6 @@ plugins {
id("androidx.navigation.safeargs.kotlin")
id("com.google.gms.oss.licenses.plugin")
id("dagger.hilt.android.plugin")
- id("io.gitlab.arturbosch.detekt")
-}
-
-dependencies {
- detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
-}
-
-detekt {
- autoCorrect = true
}
android {
@@ -23,7 +14,7 @@ android {
compileSdk = 30
defaultConfig {
applicationId = "se.eelde.toggles.example"
- minSdk = 16
+ minSdk = 21
targetSdk = 30
versionCode = 2
versionName = "1.00.01"
@@ -33,6 +24,9 @@ android {
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
+ freeCompilerArgs = listOfNotNull(
+ "-Xopt-in=kotlin.RequiresOptIn"
+ )
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -48,7 +42,7 @@ android {
applicationIdSuffix = ".debug"
}
}
- lintOptions {
+ lint {
baselineFile = file("lint-baseline.xml")
isCheckReleaseBuilds = true
isAbortOnError = true
@@ -67,35 +61,37 @@ dependencies {
testImplementation("androidx.test:rules:1.3.0")
testImplementation("androidx.test:runner:1.3.0")
testImplementation("androidx.test.ext:junit:1.1.2")
- testImplementation("org.robolectric:robolectric:4.4")
+ testImplementation("org.robolectric:robolectric:4.5.1")
- implementation("androidx.appcompat:appcompat:1.3.0-alpha02")
- implementation("com.google.android.material:material:1.3.0-beta01")
+ implementation("androidx.appcompat:appcompat:1.3.0-beta01")
+ implementation("com.google.android.material:material:1.3.0")
implementation("androidx.coordinatorlayout:coordinatorlayout:1.1.0")
implementation("androidx.constraintlayout:constraintlayout:2.0.4")
- implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.2.0")
+ implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.0")
implementation("androidx.lifecycle:lifecycle-extensions:2.2.0")
- implementation("com.google.dagger:hilt-android:2.30.1-alpha")
- kapt("com.google.dagger:hilt-android-compiler:2.30.1-alpha")
- implementation("androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02")
- kapt("androidx.hilt:hilt-compiler:1.0.0-alpha02")
- testImplementation("com.google.dagger:hilt-android-testing:2.30.1-alpha")
- kaptTest("com.google.dagger:hilt-android-compiler:2.30.1-alpha")
+ implementation("com.google.dagger:hilt-android:2.33-beta")
+ kapt("com.google.dagger:hilt-android-compiler:2.33-beta")
+ implementation("androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03")
+ kapt("androidx.hilt:hilt-compiler:1.0.0-beta01")
+ testImplementation("com.google.dagger:hilt-android-testing:2.33-beta")
+ kaptTest("com.google.dagger:hilt-android-compiler:2.33-beta")
+ implementation("androidx.lifecycle:lifecycle-common-java8:2.3.0")
- implementation("androidx.navigation:navigation-fragment-ktx:2.3.2")
- implementation("androidx.navigation:navigation-ui-ktx:2.3.2")
+ implementation("androidx.navigation:navigation-fragment-ktx:2.3.4")
+ implementation("androidx.navigation:navigation-ui-ktx:2.3.4")
implementation(project(":toggles-core"))
implementation(project(":toggles-prefs"))
- implementation(project(":toggles-coroutines"))
+ implementation(project(":toggles-flow"))
- implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.21")
- implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3")
- implementation("com.google.dagger:dagger:2.30.1")
- kapt("com.google.dagger:dagger-compiler:2.30.1")
+ implementation("com.google.dagger:dagger:2.33")
+ kapt("com.google.dagger:dagger-compiler:2.33")
implementation("com.google.android.gms:play-services-oss-licenses:17.0.0")
- implementation("androidx.core:core-ktx:1.5.0-alpha05")
+ implementation("androidx.core:core-ktx:1.3.2")
+
+ debugImplementation("com.squareup.leakcanary:leakcanary-android:2.6")
}
diff --git a/toggles-sample/lint-baseline.xml b/toggles-sample/lint-baseline.xml
index 5b2ec11c..2b1d1735 100644
--- a/toggles-sample/lint-baseline.xml
+++ b/toggles-sample/lint-baseline.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/toggles-sample/src/main/AndroidManifest.xml b/toggles-sample/src/main/AndroidManifest.xml
index 79d25631..17853a02 100644
--- a/toggles-sample/src/main/AndroidManifest.xml
+++ b/toggles-sample/src/main/AndroidManifest.xml
@@ -12,7 +12,8 @@
android:theme="@style/AppTheme"
android:name=".SampleApplication"
tools:ignore="GoogleAppIndexingWarning">
-
+
diff --git a/toggles-sample/src/main/java/com/example/wrench/di/ApplicationModule.kt b/toggles-sample/src/main/java/com/example/wrench/di/ApplicationModule.kt
index 33d5b869..0ddfb44c 100644
--- a/toggles-sample/src/main/java/com/example/wrench/di/ApplicationModule.kt
+++ b/toggles-sample/src/main/java/com/example/wrench/di/ApplicationModule.kt
@@ -8,12 +8,10 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.Dispatchers
-import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object ApplicationModule {
- @Singleton
@Provides
fun provideIoDispatcher() = Dispatchers.IO
diff --git a/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragment.kt b/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragment.kt
index 57a3847f..1df3f191 100644
--- a/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragment.kt
+++ b/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragment.kt
@@ -8,41 +8,48 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.example.wrench.databinding.FragmentLiveDataPreferencesBinding
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.ExperimentalCoroutinesApi
@AndroidEntryPoint
class LiveDataPreferencesFragment : Fragment() {
- private lateinit var binding: FragmentLiveDataPreferencesBinding
+ private var binding: FragmentLiveDataPreferencesBinding? = null
private val viewModel by viewModels()
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View =
FragmentLiveDataPreferencesBinding.inflate(inflater, container, false).also {
binding = it
}.root
- @ExperimentalCoroutinesApi
+ override fun onDestroyView() {
+ super.onDestroyView()
+ binding = null
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.getStringConfiguration().observe(viewLifecycleOwner) {
- binding.stringConfiguration.text = it
+ binding!!.stringConfiguration.text = it
}
viewModel.getUrlConfiguration().observe(viewLifecycleOwner) {
- binding.urlConfiguration.text = it
+ binding!!.urlConfiguration.text = it
}
viewModel.getBooleanConfiguration().observe(viewLifecycleOwner) {
- binding.booleanConfiguration.text = it.toString()
+ binding!!.booleanConfiguration.text = it.toString()
}
viewModel.getIntConfiguration().observe(viewLifecycleOwner) {
- binding.intConfiguration.text = it.toString()
+ binding!!.intConfiguration.text = it.toString()
}
viewModel.getEnumConfiguration().observe(viewLifecycleOwner) {
- binding.enumConfiguration.text = it.toString()
+ binding!!.enumConfiguration.text = it.toString()
}
}
}
diff --git a/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragmentViewModel.kt b/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragmentViewModel.kt
index 302bd439..bf068701 100644
--- a/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragmentViewModel.kt
+++ b/toggles-sample/src/main/java/com/example/wrench/livedataprefs/LiveDataPreferencesFragmentViewModel.kt
@@ -1,67 +1,61 @@
package com.example.wrench.livedataprefs
import android.app.Application
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.example.wrench.MyEnum
import com.example.wrench.R
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import se.eelde.toggles.coroutines.booleanBoltFlow
-import se.eelde.toggles.coroutines.enumBoltFlow
-import se.eelde.toggles.coroutines.integerBoltFlow
-import se.eelde.toggles.coroutines.stringBoltFlow
+import se.eelde.toggles.flow.toggleFlow
+import javax.inject.Inject
-class LiveDataPreferencesFragmentViewModel @ViewModelInject constructor(private val application: Application) : ViewModel() {
+@HiltViewModel
+class LiveDataPreferencesFragmentViewModel @Inject constructor(private val application: Application) : ViewModel() {
- @ExperimentalCoroutinesApi
+ @OptIn(ExperimentalCoroutinesApi::class)
private val stringConfig by lazy {
- stringBoltFlow(application, application.resources.getString(R.string.string_configuration), "string1").asLiveData(viewModelScope.coroutineContext)
+ toggleFlow(application, application.resources.getString(R.string.string_configuration), "string1").asLiveData(viewModelScope.coroutineContext)
}
- @ExperimentalCoroutinesApi
fun getStringConfiguration(): LiveData {
return stringConfig
}
- @ExperimentalCoroutinesApi
+ @OptIn(ExperimentalCoroutinesApi::class)
private val intConfig by lazy {
- integerBoltFlow(application, application.resources.getString(R.string.int_configuration), 1).asLiveData(viewModelScope.coroutineContext)
+ toggleFlow(application, application.resources.getString(R.string.int_configuration), 1).asLiveData(viewModelScope.coroutineContext)
}
- @ExperimentalCoroutinesApi
fun getIntConfiguration(): LiveData {
return intConfig
}
- @ExperimentalCoroutinesApi
+ @OptIn(ExperimentalCoroutinesApi::class)
private val booleanConfig by lazy {
- booleanBoltFlow(application, application.resources.getString(R.string.boolean_configuration), true).asLiveData(viewModelScope.coroutineContext)
+ toggleFlow(application, application.resources.getString(R.string.boolean_configuration), true).asLiveData(viewModelScope.coroutineContext)
}
- @ExperimentalCoroutinesApi
fun getBooleanConfiguration(): LiveData {
return booleanConfig
}
- @ExperimentalCoroutinesApi
+ @OptIn(ExperimentalCoroutinesApi::class)
private val urlConfig by lazy {
- stringBoltFlow(application, application.resources.getString(R.string.url_configuration), "http://www.example.com/path?param=value").asLiveData(viewModelScope.coroutineContext)
+ toggleFlow(application, application.resources.getString(R.string.url_configuration), "http://www.example.com/path?param=value").asLiveData(viewModelScope.coroutineContext)
}
- @ExperimentalCoroutinesApi
fun getUrlConfiguration(): LiveData {
return urlConfig
}
- @ExperimentalCoroutinesApi
+ @OptIn(ExperimentalCoroutinesApi::class)
private val enumConfig by lazy {
- enumBoltFlow(application, application.resources.getString(R.string.enum_configuration), MyEnum::class.java, MyEnum.FIRST).asLiveData(viewModelScope.coroutineContext)
+ toggleFlow(application, application.resources.getString(R.string.enum_configuration), MyEnum::class.java, MyEnum.FIRST).asLiveData(viewModelScope.coroutineContext)
}
- @ExperimentalCoroutinesApi
fun getEnumConfiguration(): LiveData {
return enumConfig
}
diff --git a/toggles-sample/src/main/java/com/example/wrench/wrenchprefs/WrenchPreferencesFragmentViewModel.kt b/toggles-sample/src/main/java/com/example/wrench/wrenchprefs/WrenchPreferencesFragmentViewModel.kt
index 6c47b403..23dc8f2a 100644
--- a/toggles-sample/src/main/java/com/example/wrench/wrenchprefs/WrenchPreferencesFragmentViewModel.kt
+++ b/toggles-sample/src/main/java/com/example/wrench/wrenchprefs/WrenchPreferencesFragmentViewModel.kt
@@ -1,19 +1,21 @@
package com.example.wrench.wrenchprefs
import android.app.Application
-import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.wrench.MyEnum
import com.example.wrench.R
import com.izettle.wrench.preferences.ITogglesPreferences
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+import javax.inject.Inject
-class WrenchPreferencesFragmentViewModel @ViewModelInject internal constructor(
+@HiltViewModel
+class WrenchPreferencesFragmentViewModel @Inject internal constructor(
private val application: Application,
private val togglesPreferences: ITogglesPreferences
) : ViewModel() {
diff --git a/toggles-sample/src/main/res/drawable/ic_flow_24.xml b/toggles-sample/src/main/res/drawable/ic_flow_24.xml
new file mode 100644
index 00000000..6685df37
--- /dev/null
+++ b/toggles-sample/src/main/res/drawable/ic_flow_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/toggles-sample/src/main/res/drawable/ic_live_data_24dp.xml b/toggles-sample/src/main/res/drawable/ic_live_data_24dp.xml
deleted file mode 100644
index 6fe51d9b..00000000
--- a/toggles-sample/src/main/res/drawable/ic_live_data_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/toggles-sample/src/main/res/drawable/ic_prefs_24.xml b/toggles-sample/src/main/res/drawable/ic_prefs_24.xml
new file mode 100644
index 00000000..8f9bb964
--- /dev/null
+++ b/toggles-sample/src/main/res/drawable/ic_prefs_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/toggles-sample/src/main/res/drawable/ic_wrench_prefs_24dp.xml b/toggles-sample/src/main/res/drawable/ic_wrench_prefs_24dp.xml
deleted file mode 100644
index 5cc6e236..00000000
--- a/toggles-sample/src/main/res/drawable/ic_wrench_prefs_24dp.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
diff --git a/toggles-sample/src/main/res/layout/fragment_live_data_preferences.xml b/toggles-sample/src/main/res/layout/fragment_live_data_preferences.xml
index 8d67dcaf..98691f8c 100644
--- a/toggles-sample/src/main/res/layout/fragment_live_data_preferences.xml
+++ b/toggles-sample/src/main/res/layout/fragment_live_data_preferences.xml
@@ -36,7 +36,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
- android:layout_marginTop="0dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:padding="8dp"
diff --git a/toggles-sample/src/main/res/menu/main_activity_navigation.xml b/toggles-sample/src/main/res/menu/main_activity_navigation.xml
index e39b04da..08118aa4 100644
--- a/toggles-sample/src/main/res/menu/main_activity_navigation.xml
+++ b/toggles-sample/src/main/res/menu/main_activity_navigation.xml
@@ -2,12 +2,12 @@
enum configuration:
- Live data
- Prefs
+ Flow
+ Prefs
oss