From 3a92ed602a9c4c78a4dcff2097259a58da7489b6 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Mon, 17 Nov 2025 11:07:32 +0530 Subject: [PATCH 01/21] refactor: data folder --- .../passcodes/autofill/PasswordAutofillService.kt | 4 ++-- .../jeeldobariya/passcodes/{ => autofill}/data/Passcode.kt | 2 +- .../jeeldobariya/passcodes/{ => autofill}/data/PasscodeDao.kt | 2 +- .../passcodes/{ => autofill}/data/PasscodeDatabase.kt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename app/src/main/kotlin/com/jeeldobariya/passcodes/{ => autofill}/data/Passcode.kt (81%) rename app/src/main/kotlin/com/jeeldobariya/passcodes/{ => autofill}/data/PasscodeDao.kt (93%) rename app/src/main/kotlin/com/jeeldobariya/passcodes/{ => autofill}/data/PasscodeDatabase.kt (94%) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt index 85af800b..0f3c8787 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/PasswordAutofillService.kt @@ -11,8 +11,8 @@ import android.service.autofill.SaveRequest import android.view.autofill.AutofillValue import android.widget.RemoteViews import com.jeeldobariya.passcodes.R -import com.jeeldobariya.passcodes.data.Passcode -import com.jeeldobariya.passcodes.data.PasscodeDatabase +import com.jeeldobariya.passcodes.autofill.data.Passcode +import com.jeeldobariya.passcodes.autofill.data.PasscodeDatabase import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/data/Passcode.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt similarity index 81% rename from app/src/main/kotlin/com/jeeldobariya/passcodes/data/Passcode.kt rename to app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt index e175e96f..61a37394 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/data/Passcode.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/Passcode.kt @@ -1,4 +1,4 @@ -package com.jeeldobariya.passcodes.data +package com.jeeldobariya.passcodes.autofill.data import androidx.room.Entity import androidx.room.PrimaryKey diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/data/PasscodeDao.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt similarity index 93% rename from app/src/main/kotlin/com/jeeldobariya/passcodes/data/PasscodeDao.kt rename to app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt index 957d5a37..9519602d 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/data/PasscodeDao.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDao.kt @@ -1,4 +1,4 @@ -package com.jeeldobariya.passcodes.data +package com.jeeldobariya.passcodes.autofill.data import androidx.room.Dao import androidx.room.Delete diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/data/PasscodeDatabase.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt similarity index 94% rename from app/src/main/kotlin/com/jeeldobariya/passcodes/data/PasscodeDatabase.kt rename to app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt index 1fe03c95..e81ca689 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/data/PasscodeDatabase.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/autofill/data/PasscodeDatabase.kt @@ -1,4 +1,4 @@ -package com.jeeldobariya.passcodes.data +package com.jeeldobariya.passcodes.autofill.data import android.content.Context import androidx.room.Database From e4fd22c46f58b16f2f7250c16776a26285a3fd9b Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 09:28:27 +0530 Subject: [PATCH 02/21] chore(deps): add a datastore dependency --- app/build.gradle.kts | 3 +++ gradle/libs.versions.toml | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d71aa566..ec725911 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -194,6 +194,9 @@ dependencies { // Dependency Injection implementation(libs.bundles.koin) + // DataStore + implementation(libs.bundles.android.datastore) + // --- Testing --- diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f964c6e2..68aaab72 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,6 @@ [versions] kotlin = "2.2.21" +datastore = "1.1.7" material = "1.13.0" okhttp = "5.3.0" oss-license = "17.3.0" @@ -19,6 +20,7 @@ compose-viewmodel = "2.9.4" nav3Core = "1.0.0-rc01" lifecycleViewmodelNav3 = "2.10.0-rc01" material3AdaptiveNav3 = "1.3.0-alpha03" +koltinxSerializationJson = "1.3.2" # Plugin versions agp = "8.13.1" @@ -49,6 +51,10 @@ material = { group = "com.google.android.material", name = "material", version.r oss-license = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "oss-license" } appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +# DataStore +androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } +koltinx-serialization-json = { module = "org.jetbrains.kotlinx:koltinx-serialization-json", version.ref = "koltinxSerializationJson" } + # Room room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } @@ -106,6 +112,9 @@ koin = ["koin", "koin-compose"] unit-test = ["junit", "truth"] android-test = ["androidx-test-ext-junit", "espresso-core"] +# Grouping Datastore +android-datastore = ["androidx-datastore", "koltinx-serialization-json"] + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 85a98a943b5fe02488b4bb9ba3a19a5639e3f83c Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 10:42:24 +0530 Subject: [PATCH 03/21] Revert "chore(deps): add a datastore dependency" This reverts commit e4fd22c46f58b16f2f7250c16776a26285a3fd9b. --- app/build.gradle.kts | 3 --- gradle/libs.versions.toml | 9 --------- 2 files changed, 12 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ec725911..d71aa566 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -194,9 +194,6 @@ dependencies { // Dependency Injection implementation(libs.bundles.koin) - // DataStore - implementation(libs.bundles.android.datastore) - // --- Testing --- diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 68aaab72..f964c6e2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,5 @@ [versions] kotlin = "2.2.21" -datastore = "1.1.7" material = "1.13.0" okhttp = "5.3.0" oss-license = "17.3.0" @@ -20,7 +19,6 @@ compose-viewmodel = "2.9.4" nav3Core = "1.0.0-rc01" lifecycleViewmodelNav3 = "2.10.0-rc01" material3AdaptiveNav3 = "1.3.0-alpha03" -koltinxSerializationJson = "1.3.2" # Plugin versions agp = "8.13.1" @@ -51,10 +49,6 @@ material = { group = "com.google.android.material", name = "material", version.r oss-license = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "oss-license" } appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } -# DataStore -androidx-datastore = { module = "androidx.datastore:datastore", version.ref = "datastore" } -koltinx-serialization-json = { module = "org.jetbrains.kotlinx:koltinx-serialization-json", version.ref = "koltinxSerializationJson" } - # Room room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } @@ -112,9 +106,6 @@ koin = ["koin", "koin-compose"] unit-test = ["junit", "truth"] android-test = ["androidx-test-ext-junit", "espresso-core"] -# Grouping Datastore -android-datastore = ["androidx-datastore", "koltinx-serialization-json"] - [plugins] android-application = { id = "com.android.application", version.ref = "agp" } From 1e196e3111be37d731ea356fcd01887d3ca386f7 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 17:56:11 +0530 Subject: [PATCH 04/21] chore: improve build script --- app/build.gradle.kts | 41 ++++++++----------- .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 ++- gradle/libs.versions.toml | 3 +- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d71aa566..265028a3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,7 +14,7 @@ plugins { kotlin { compilerOptions { - jvmTarget = JvmTarget.JVM_21 + jvmTarget.set(JvmTarget.JVM_21) } } @@ -90,6 +90,8 @@ android { // throw GradleException("Can't Sign Release Build") } + isDebuggable = false + isShrinkResources = true isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") @@ -101,10 +103,13 @@ android { getByName("debug") { applicationIdSuffix = ".dev" versionNameSuffix = "-Dev" + + isDebuggable = true + isShrinkResources = false isMinifyEnabled = false - manifestPlaceholders["appIcon"] = "@mipmap/dev_ic_launcher" - manifestPlaceholders["appLabel"] = "Passcodes Dev" + manifestPlaceholders["appIcon"] = "@drawable/dev_ic_launcher_foreground" + manifestPlaceholders["appLabel"] = "Passcodes-Dev" } create("staging") { @@ -118,35 +123,25 @@ android { applicationIdSuffix = ".staging" versionNameSuffix = "-Staging" - isMinifyEnabled = true - isShrinkResources = true isDebuggable = false + isShrinkResources = true + isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - manifestPlaceholders["appIcon"] = "@mipmap/dev_ic_launcher" - manifestPlaceholders["appLabel"] = "Passcodes Staging" + manifestPlaceholders["appIcon"] = "@drawable/dev_ic_launcher_foreground" + manifestPlaceholders["appLabel"] = "Passcodes-Staging" } } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 - } - - buildFeatures { - viewBinding = true - buildConfig = true - compose = true - } } + compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - kotlinOptions { - jvmTarget = "11" + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } + buildFeatures { + viewBinding = true + buildConfig = true compose = true } diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index eca70cfe..345888d2 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,6 @@ - - + + + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f964c6e2..14f17c4e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,6 @@ material3AdaptiveNav3 = "1.3.0-alpha03" # Plugin versions agp = "8.13.1" -kotlin-plugin = "2.2.21" ksp = "2.3.2" oss-license-plugin = "0.10.9" # Also update in settings.gradle.kts @@ -109,7 +108,7 @@ android-test = ["androidx-test-ext-junit", "espresso-core"] [plugins] android-application = { id = "com.android.application", version.ref = "agp" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin-plugin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } oss-licenses = { id = "com.google.android.gms.oss-licenses-plugin", version.ref = "oss-license-plugin" } From 162d72989698ada85a9856220795b39f22c431e6 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 18:27:59 +0530 Subject: [PATCH 05/21] chore(deps): add datastore preference as dependency --- app/build.gradle.kts | 6 +++++- build.gradle.kts | 5 +++-- gradle/libs.versions.toml | 29 ++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 265028a3..fd398410 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -7,7 +7,8 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) - alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.jetbrains.kotlin.serialization) alias(libs.plugins.ksp) alias(libs.plugins.oss.licenses) } @@ -189,6 +190,9 @@ dependencies { // Dependency Injection implementation(libs.bundles.koin) + // Datastore Preferences + implementation(libs.bundles.datastore.preferences) + // --- Testing --- diff --git a/build.gradle.kts b/build.gradle.kts index 81899815..0dc3239c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,12 +1,13 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false - alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.jetbrains.kotlin.serialization) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.oss.licenses) apply false } -// Allprojects block is common for setting up common repositories for all subprojects. +// All projects block is common for setting up common repositories for all subprojects. allprojects { repositories { google() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 14f17c4e..01c99cb4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,12 +19,16 @@ compose-viewmodel = "2.9.4" nav3Core = "1.0.0-rc01" lifecycleViewmodelNav3 = "2.10.0-rc01" material3AdaptiveNav3 = "1.3.0-alpha03" +datastorePreferences = "1.1.7" +kotlinSerializationJson = "1.9.0" # Plugin versions agp = "8.13.1" ksp = "2.3.2" oss-license-plugin = "0.10.9" # Also update in settings.gradle.kts + + [libraries] # Kotlin Std libs kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } @@ -48,6 +52,10 @@ material = { group = "com.google.android.material", name = "material", version.r oss-license = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "oss-license" } appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +# DataStore Preference +androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinSerializationJson" } + # Room room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } @@ -69,6 +77,7 @@ lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmode koin = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } +# Json json = { group = "org.json", name = "json", version.ref = "json" } # Testing @@ -82,33 +91,39 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } + [bundles] -# Grouping Jetpack Compose Dependencies +# Jetpack Compose Dependencies compose = ["compose-ui-material", "compose-ui-preview", "compose-activity", "compose-viewmodel"] compose-debug = ["compose-ui-tooling-debug"] -# Grouping Navigation 3 Dependencies +# Navigation 3 Dependencies navigation3 = ["androidx-navigation3-runtime", "androidx-navigation3-ui", "androidx-lifecycle-viewmodel-navigation3", "androidx-material3-adaptive-navigation3"] -# Grouping Android Architecture Releated Components +# Android Architecture Releated Components room = ["room-ktx", "room-testing"] lifecycle = ["lifecycle-runtime", "lifecycle-viewmodel"] -# Grouping Coroutines Dependencies +# DataStore Preference +datastore-preferences = ["androidx-datastore-preferences", "kotlinx-serialization-json"] + +# Coroutines Dependencies coroutines = ["coroutines-core", "coroutines-android"] coroutines-test = ["coroutines-core", "coroutines-test"] -# Grouping Dependency Injection Dependencies +# Dependency Injection Dependencies koin = ["koin", "koin-compose"] -# Grouping General Test Dependencies +# General Test Dependencies unit-test = ["junit", "truth"] android-test = ["androidx-test-ext-junit", "espresso-core"] + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } oss-licenses = { id = "com.google.android.gms.oss-licenses-plugin", version.ref = "oss-license-plugin" } From a9b120a722c98cfc0dd2e17a8d509f07b022b86a Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 18:30:38 +0530 Subject: [PATCH 06/21] chore(deps): okhttp 5.3.0 -> 5.3.2 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 01c99cb4..4f06ce93 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] kotlin = "2.2.21" material = "1.13.0" -okhttp = "5.3.0" +okhttp = "5.3.2" oss-license = "17.3.0" appcompat = "1.7.1" room = "2.8.3" From fb69f9b801e4fdbe86f552c6aa3c95e7e958ac57 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 18:58:31 +0530 Subject: [PATCH 07/21] feat: make a datastore for feature flags --- .../passcodes/flags/FeatureFlagsSettings.kt | 9 +++++ .../flags/FeatureFlagsSettingsSerializer.kt | 36 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt create mode 100644 app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt new file mode 100644 index 00000000..cbb56e61 --- /dev/null +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt @@ -0,0 +1,9 @@ +package com.jeeldobariya.passcodes.flags + +import kotlinx.serialization.Serializable + +@Serializable +data class FeatureFlagsSettings( + val isPreviewFeaturesEnabled: Boolean, + val isPreviewLayoutEnabled: Boolean +) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt new file mode 100644 index 00000000..145c18a6 --- /dev/null +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt @@ -0,0 +1,36 @@ +package com.jeeldobariya.passcodes.flags + +import androidx.datastore.core.Serializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json +import java.io.InputStream +import java.io.OutputStream + +object FeatureFlagsSettingsSerializer: Serializer { + override val defaultValue: FeatureFlagsSettings + get() = FeatureFlagsSettings(false, false) + + override suspend fun readFrom(input: InputStream): FeatureFlagsSettings { + return try { + Json.decodeFromString( + deserializer = FeatureFlagsSettings.serializer(), + string = input.readBytes().decodeToString(), + ) + } catch (e: SerializationException) { + e.printStackTrace() + defaultValue + } + } + + override suspend fun writeTo( + t: FeatureFlagsSettings, + output: OutputStream + ) { + output.write( + Json.encodeToString( + serializer = FeatureFlagsSettings.serializer(), + value = t + ).encodeToByteArray() + ) + } +} From 6eb481eef0fca8682fdc76d007e43812011a119d Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Wed, 19 Nov 2025 19:22:10 +0530 Subject: [PATCH 08/21] feat: use feature flag datastore --- .../passcodes/flags/FeatureFlagManager.kt | 29 +++++++++++++++++-- .../oldui/PasswordManagerActivity.kt | 14 +++++---- .../passcodes/oldui/SettingsActivity.kt | 13 +++++++-- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt index b42f0a89..b24bd665 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt @@ -1,10 +1,34 @@ package com.jeeldobariya.passcodes.flags import android.content.Context -import androidx.core.content.edit -import com.jeeldobariya.passcodes.utils.Constant +import androidx.datastore.dataStore +import kotlinx.coroutines.flow.first +val Context.featureFlagsDatastore by dataStore(fileName = "feature-flags-settings.json", serializer = FeatureFlagsSettingsSerializer) + +suspend fun Context.isPreviewFeaturesEnable(): Boolean { + return featureFlagsDatastore.data.first().isPreviewFeaturesEnabled +} + +suspend fun Context.togglePreviewFeatures(): Boolean { + return featureFlagsDatastore.updateData { + it.copy(isPreviewFeaturesEnabled = !it.isPreviewFeaturesEnabled) + }.isPreviewFeaturesEnabled +} + +suspend fun Context.isPreviewLayoutEnable(): Boolean { + return featureFlagsDatastore.data.first().isPreviewLayoutEnabled +} + +suspend fun Context.togglePreviewLayout(): Boolean { + return featureFlagsDatastore.updateData { + it.copy(isPreviewLayoutEnabled = !it.isPreviewLayoutEnabled) + }.isPreviewLayoutEnabled +} + +/* class FeatureFlagManager private constructor(context: Context) { + private val prefs = context.getSharedPreferences(Constant.FEATURE_FLAGS_PREFS_NAME, Context.MODE_PRIVATE) @@ -27,3 +51,4 @@ class FeatureFlagManager private constructor(context: Context) { } } } +*/ diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt index f13ee291..ed959c47 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt @@ -11,7 +11,7 @@ import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivityPasswordManagerBinding -import com.jeeldobariya.passcodes.flags.FeatureFlagManager +import com.jeeldobariya.passcodes.flags.isPreviewFeaturesEnable import com.jeeldobariya.passcodes.utils.CommonUtils import com.jeeldobariya.passcodes.utils.Controller import kotlinx.coroutines.Dispatchers @@ -35,11 +35,6 @@ class PasswordManagerActivity : AppCompatActivity() { binding = ActivityPasswordManagerBinding.inflate(layoutInflater) setContentView(binding.root) - if (!FeatureFlagManager.get(this).latestFeaturesEnabled) { - binding.importPasswordBtn.visibility = GONE - binding.exportPasswordBtn.visibility = GONE - } - controller = Controller(this) // Initialize the controller here importCsvLauncher = registerForActivityResult( @@ -103,6 +98,13 @@ class PasswordManagerActivity : AppCompatActivity() { } } + lifecycleScope.launch { + if (isPreviewFeaturesEnable()) { + binding.importPasswordBtn.visibility = GONE + binding.exportPasswordBtn.visibility = GONE + } + } + // Add event onclick listener addOnClickListenerOnButton(binding) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt index 76adb186..92ef61dc 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt @@ -12,10 +12,11 @@ import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivitySettingsBinding -import com.jeeldobariya.passcodes.flags.FeatureFlagManager +import com.jeeldobariya.passcodes.flags.featureFlagsDatastore import com.jeeldobariya.passcodes.utils.CommonUtils import com.jeeldobariya.passcodes.utils.Constant import com.jeeldobariya.passcodes.utils.Controller +import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow import kotlinx.coroutines.launch class SettingsActivity : AppCompatActivity() { @@ -40,7 +41,9 @@ class SettingsActivity : AppCompatActivity() { setInitialLangSelection() - binding.switchLatestFeatures.isChecked = FeatureFlagManager.get(this).latestFeaturesEnabled + collectLatestLifecycleFlow(featureFlagsDatastore.data) { + binding.switchLatestFeatures.isChecked = !it.isPreviewFeaturesEnabled + } controller = Controller(this) // Initialize the controller here @@ -112,7 +115,11 @@ class SettingsActivity : AppCompatActivity() { } binding.switchLatestFeatures.setOnCheckedChangeListener { _, isChecked -> - FeatureFlagManager.get(this).latestFeaturesEnabled = isChecked + lifecycleScope.launch { + featureFlagsDatastore.updateData { + it.copy(isPreviewLayoutEnabled = !isChecked) + } + } Toast.makeText( this@SettingsActivity, getString(R.string.future_feat_clause) + isChecked.toString(), From 3d6f63df4ecbbc501edb5eab6d48418ed481890f Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 17:14:24 +0530 Subject: [PATCH 09/21] chore: remove toggling feature flag function --- .../passcodes/flags/FeatureFlagManager.kt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt index b24bd665..01a24274 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt @@ -10,22 +10,10 @@ suspend fun Context.isPreviewFeaturesEnable(): Boolean { return featureFlagsDatastore.data.first().isPreviewFeaturesEnabled } -suspend fun Context.togglePreviewFeatures(): Boolean { - return featureFlagsDatastore.updateData { - it.copy(isPreviewFeaturesEnabled = !it.isPreviewFeaturesEnabled) - }.isPreviewFeaturesEnabled -} - suspend fun Context.isPreviewLayoutEnable(): Boolean { return featureFlagsDatastore.data.first().isPreviewLayoutEnabled } -suspend fun Context.togglePreviewLayout(): Boolean { - return featureFlagsDatastore.updateData { - it.copy(isPreviewLayoutEnabled = !it.isPreviewLayoutEnabled) - }.isPreviewLayoutEnabled -} - /* class FeatureFlagManager private constructor(context: Context) { From 44b89153133d01ba156e85038392d3beba150274 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 17:19:24 +0530 Subject: [PATCH 10/21] feat: made password manager activity stateflow based --- .../jeeldobariya/passcodes/flags/FeatureFlagManager.kt | 9 --------- .../passcodes/oldui/PasswordManagerActivity.kt | 7 ++++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt index 01a24274..714ae4af 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt @@ -2,18 +2,9 @@ package com.jeeldobariya.passcodes.flags import android.content.Context import androidx.datastore.dataStore -import kotlinx.coroutines.flow.first val Context.featureFlagsDatastore by dataStore(fileName = "feature-flags-settings.json", serializer = FeatureFlagsSettingsSerializer) -suspend fun Context.isPreviewFeaturesEnable(): Boolean { - return featureFlagsDatastore.data.first().isPreviewFeaturesEnabled -} - -suspend fun Context.isPreviewLayoutEnable(): Boolean { - return featureFlagsDatastore.data.first().isPreviewLayoutEnabled -} - /* class FeatureFlagManager private constructor(context: Context) { diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt index ed959c47..a87e9f46 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt @@ -11,9 +11,10 @@ import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivityPasswordManagerBinding -import com.jeeldobariya.passcodes.flags.isPreviewFeaturesEnable +import com.jeeldobariya.passcodes.flags.featureFlagsDatastore import com.jeeldobariya.passcodes.utils.CommonUtils import com.jeeldobariya.passcodes.utils.Controller +import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -98,8 +99,8 @@ class PasswordManagerActivity : AppCompatActivity() { } } - lifecycleScope.launch { - if (isPreviewFeaturesEnable()) { + collectLatestLifecycleFlow(featureFlagsDatastore.data) { + if (!it.isPreviewFeaturesEnabled) { binding.importPasswordBtn.visibility = GONE binding.exportPasswordBtn.visibility = GONE } From ebe5b94050d0ecc2c11d6835a212b74684d8ad71 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 17:21:14 +0530 Subject: [PATCH 11/21] fix the error with preview feature toggle --- .../com/jeeldobariya/passcodes/oldui/SettingsActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt index 92ef61dc..ba221627 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt @@ -42,7 +42,7 @@ class SettingsActivity : AppCompatActivity() { setInitialLangSelection() collectLatestLifecycleFlow(featureFlagsDatastore.data) { - binding.switchLatestFeatures.isChecked = !it.isPreviewFeaturesEnabled + binding.switchLatestFeatures.isChecked = it.isPreviewFeaturesEnabled } controller = Controller(this) // Initialize the controller here @@ -117,7 +117,7 @@ class SettingsActivity : AppCompatActivity() { binding.switchLatestFeatures.setOnCheckedChangeListener { _, isChecked -> lifecycleScope.launch { featureFlagsDatastore.updateData { - it.copy(isPreviewLayoutEnabled = !isChecked) + it.copy(isPreviewFeaturesEnabled = isChecked) } } Toast.makeText( From af1f30b93c7032b67097478da34631288634e2ab Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 17:50:02 +0530 Subject: [PATCH 12/21] feat: made a app setting datapreference --- .../passcodes/flags/FeatureFlagManager.kt | 33 ----------------- .../passcodes/flags/FeatureFlagsSettings.kt | 4 +++ .../flags/FeatureFlagsSettingsSerializer.kt | 4 +-- .../passcodes/utils/AppSettings.kt | 12 +++++++ .../passcodes/utils/AppSettingsSerializer.kt | 36 +++++++++++++++++++ 5 files changed, 54 insertions(+), 35 deletions(-) delete mode 100644 app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt create mode 100644 app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt create mode 100644 app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt deleted file mode 100644 index 714ae4af..00000000 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagManager.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.jeeldobariya.passcodes.flags - -import android.content.Context -import androidx.datastore.dataStore - -val Context.featureFlagsDatastore by dataStore(fileName = "feature-flags-settings.json", serializer = FeatureFlagsSettingsSerializer) - -/* -class FeatureFlagManager private constructor(context: Context) { - - private val prefs = - context.getSharedPreferences(Constant.FEATURE_FLAGS_PREFS_NAME, Context.MODE_PRIVATE) - - var latestFeaturesEnabled: Boolean - get() = prefs.getBoolean(Constant.LATEST_FEATURES_KEY, false) - set(value) { - prefs.edit { putBoolean(Constant.LATEST_FEATURES_KEY, value) } - } - - companion object { - @Volatile - private var INSTANCE: FeatureFlagManager? = null - - fun get(context: Context): FeatureFlagManager { - return INSTANCE ?: synchronized(this) { - val instance = FeatureFlagManager(context.applicationContext) - INSTANCE = instance - instance - } - } - } -} -*/ diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt index cbb56e61..506e3193 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt @@ -1,7 +1,11 @@ package com.jeeldobariya.passcodes.flags +import android.content.Context +import androidx.datastore.dataStore import kotlinx.serialization.Serializable +val Context.featureFlagsDatastore by dataStore(fileName = "feature-flags-settings-v1.json", serializer = FeatureFlagsSettingsSerializer) + @Serializable data class FeatureFlagsSettings( val isPreviewFeaturesEnabled: Boolean, diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt index 145c18a6..fc8af85a 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt @@ -1,6 +1,6 @@ package com.jeeldobariya.passcodes.flags -import androidx.datastore.core.Serializer +import androidx.datastore.core.Serializer import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import java.io.InputStream @@ -8,7 +8,7 @@ import java.io.OutputStream object FeatureFlagsSettingsSerializer: Serializer { override val defaultValue: FeatureFlagsSettings - get() = FeatureFlagsSettings(false, false) + get() = FeatureFlagsSettings(isPreviewFeaturesEnabled = false, isPreviewLayoutEnabled = false) override suspend fun readFrom(input: InputStream): FeatureFlagsSettings { return try { diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt new file mode 100644 index 00000000..9421383d --- /dev/null +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt @@ -0,0 +1,12 @@ +package com.jeeldobariya.passcodes.utils + +import android.content.Context +import androidx.datastore.dataStore +import kotlinx.serialization.Serializable + +val Context.appDatastore by dataStore(fileName = "app-settings-v1.json", serializer = AppSettingsSerializer) + +@Serializable +data class AppSettings( + val theme: String +) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt new file mode 100644 index 00000000..9581c2a2 --- /dev/null +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt @@ -0,0 +1,36 @@ +package com.jeeldobariya.passcodes.utils + +import androidx.datastore.core.Serializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.Json +import java.io.InputStream +import java.io.OutputStream + +object AppSettingsSerializer: Serializer { + override val defaultValue: AppSettings + get() = AppSettings(theme = "") + + override suspend fun readFrom(input: InputStream): AppSettings { + return try { + Json.decodeFromString( + deserializer = AppSettings.serializer(), + string = input.readBytes().decodeToString(), + ) + } catch (e: SerializationException) { + e.printStackTrace() + defaultValue + } + } + + override suspend fun writeTo( + t: AppSettings, + output: OutputStream + ) { + output.write( + Json.encodeToString( + serializer = AppSettings.serializer(), + value = t + ).encodeToByteArray() + ) + } +} From 60be33410b923fc39fea3f1552556b490b2153b3 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 17:58:48 +0530 Subject: [PATCH 13/21] refactor: add defualt value for feature flags settings --- .../com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt | 4 ++-- .../passcodes/flags/FeatureFlagsSettingsSerializer.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt index 506e3193..88860158 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt @@ -8,6 +8,6 @@ val Context.featureFlagsDatastore by dataStore(fileName = "feature-flags-setting @Serializable data class FeatureFlagsSettings( - val isPreviewFeaturesEnabled: Boolean, - val isPreviewLayoutEnabled: Boolean + val isPreviewFeaturesEnabled: Boolean = false, + val isPreviewLayoutEnabled: Boolean = false ) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt index fc8af85a..187978c1 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettingsSerializer.kt @@ -8,7 +8,7 @@ import java.io.OutputStream object FeatureFlagsSettingsSerializer: Serializer { override val defaultValue: FeatureFlagsSettings - get() = FeatureFlagsSettings(isPreviewFeaturesEnabled = false, isPreviewLayoutEnabled = false) + get() = FeatureFlagsSettings() override suspend fun readFrom(input: InputStream): FeatureFlagsSettings { return try { From 429efc08dcdbc77ee232a8b976bc1de71838d060 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 21:04:38 +0530 Subject: [PATCH 14/21] feat: add a defualt value --- .../kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt | 3 ++- .../com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt index 9421383d..7d3edf5d 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt @@ -2,11 +2,12 @@ package com.jeeldobariya.passcodes.utils import android.content.Context import androidx.datastore.dataStore +import com.jeeldobariya.passcodes.R import kotlinx.serialization.Serializable val Context.appDatastore by dataStore(fileName = "app-settings-v1.json", serializer = AppSettingsSerializer) @Serializable data class AppSettings( - val theme: String + val theme: Int = R.style.PasscodesTheme_Default, ) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt index 9581c2a2..a8c03f9a 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettingsSerializer.kt @@ -8,7 +8,7 @@ import java.io.OutputStream object AppSettingsSerializer: Serializer { override val defaultValue: AppSettings - get() = AppSettings(theme = "") + get() = AppSettings() override suspend fun readFrom(input: InputStream): AppSettings { return try { From f356283f2a38941461b25db43e52a1a9fe434176 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Thu, 20 Nov 2025 21:14:34 +0530 Subject: [PATCH 15/21] feat: use the datastore for the theme app setting --- .../passcodes/oldui/AboutUsActivity.kt | 8 +++-- .../passcodes/oldui/LicenseActivity.kt | 10 ++++-- .../passcodes/oldui/LoadPasswordActivity.kt | 8 +++-- .../passcodes/oldui/MainActivity.kt | 8 +++-- .../oldui/PasswordManagerActivity.kt | 8 +++-- .../passcodes/oldui/SavePasswordActivity.kt | 8 +++-- .../passcodes/oldui/SettingsActivity.kt | 33 +++++++++---------- .../passcodes/oldui/UpdatePasswordActivity.kt | 8 +++-- .../passcodes/oldui/ViewPasswordActivity.kt | 7 ++-- .../passcodes/utils/CommonUtils.kt | 20 ----------- 10 files changed, 63 insertions(+), 55 deletions(-) delete mode 100644 app/src/main/kotlin/com/jeeldobariya/passcodes/utils/CommonUtils.kt diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/AboutUsActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/AboutUsActivity.kt index c4ef8a2d..462ec85f 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/AboutUsActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/AboutUsActivity.kt @@ -5,15 +5,19 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.net.toUri import com.jeeldobariya.passcodes.databinding.ActivityAboutUsBinding -import com.jeeldobariya.passcodes.utils.CommonUtils import com.jeeldobariya.passcodes.utils.Constant +import com.jeeldobariya.passcodes.utils.appDatastore +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking class AboutUsActivity : AppCompatActivity() { private lateinit var binding: ActivityAboutUsBinding override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivityAboutUsBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LicenseActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LicenseActivity.kt index d31bd781..042c23d4 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LicenseActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LicenseActivity.kt @@ -5,16 +5,20 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.google.android.gms.oss.licenses.OssLicensesMenuActivity import com.jeeldobariya.passcodes.databinding.ActivityLicenseBinding -import com.jeeldobariya.passcodes.utils.CommonUtils +import com.jeeldobariya.passcodes.utils.appDatastore +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import java.io.BufferedReader import java.io.InputStreamReader class LicenseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) - var binding = ActivityLicenseBinding.inflate(layoutInflater) + val binding = ActivityLicenseBinding.inflate(layoutInflater) setContentView(binding.root) try { diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LoadPasswordActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LoadPasswordActivity.kt index ef30c244..e2d48a83 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LoadPasswordActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/LoadPasswordActivity.kt @@ -9,8 +9,10 @@ import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.database.Password import com.jeeldobariya.passcodes.databinding.ActivityLoadPasswordBinding import com.jeeldobariya.passcodes.oldui.adapter.PasswordAdapter -import com.jeeldobariya.passcodes.utils.CommonUtils +import com.jeeldobariya.passcodes.utils.appDatastore import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import org.koin.androidx.viewmodel.ext.android.viewModel class LoadPasswordActivity : AppCompatActivity() { @@ -21,7 +23,9 @@ class LoadPasswordActivity : AppCompatActivity() { private lateinit var passwordAdapter: PasswordAdapter override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivityLoadPasswordBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt index 0c6a9fb1..881afa13 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt @@ -7,10 +7,12 @@ import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope import com.jeeldobariya.passcodes.BuildConfig import com.jeeldobariya.passcodes.databinding.ActivityMainBinding -import com.jeeldobariya.passcodes.utils.CommonUtils import com.jeeldobariya.passcodes.utils.UpdateChecker +import com.jeeldobariya.passcodes.utils.appDatastore import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking // import com.jeeldobariya.passcodes.utils.Permissions @@ -21,7 +23,9 @@ class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt index a87e9f46..0566e216 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/PasswordManagerActivity.kt @@ -12,11 +12,13 @@ import androidx.lifecycle.lifecycleScope import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivityPasswordManagerBinding import com.jeeldobariya.passcodes.flags.featureFlagsDatastore -import com.jeeldobariya.passcodes.utils.CommonUtils import com.jeeldobariya.passcodes.utils.Controller +import com.jeeldobariya.passcodes.utils.appDatastore import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -31,7 +33,9 @@ class PasswordManagerActivity : AppCompatActivity() { private lateinit var importCsvLauncher: ActivityResultLauncher override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivityPasswordManagerBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SavePasswordActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SavePasswordActivity.kt index 9833cade..d5a012f7 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SavePasswordActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SavePasswordActivity.kt @@ -5,7 +5,9 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivitySavePasswordBinding -import com.jeeldobariya.passcodes.utils.CommonUtils +import com.jeeldobariya.passcodes.utils.appDatastore +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import org.koin.androidx.viewmodel.ext.android.viewModel class SavePasswordActivity : AppCompatActivity() { @@ -15,7 +17,9 @@ class SavePasswordActivity : AppCompatActivity() { private lateinit var binding: ActivitySavePasswordBinding override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivitySavePasswordBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt index ba221627..8ba4be4c 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/SettingsActivity.kt @@ -6,18 +6,18 @@ import android.widget.AdapterView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate -import androidx.core.content.edit import androidx.core.os.LocaleListCompat import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivitySettingsBinding import com.jeeldobariya.passcodes.flags.featureFlagsDatastore -import com.jeeldobariya.passcodes.utils.CommonUtils -import com.jeeldobariya.passcodes.utils.Constant import com.jeeldobariya.passcodes.utils.Controller +import com.jeeldobariya.passcodes.utils.appDatastore import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking class SettingsActivity : AppCompatActivity() { @@ -34,7 +34,9 @@ class SettingsActivity : AppCompatActivity() { ) override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivitySettingsBinding.inflate(layoutInflater) setContentView(binding.root) @@ -66,11 +68,6 @@ class SettingsActivity : AppCompatActivity() { } binding.langSwitchDropdown.setSelection(0) - Toast.makeText( - this@SettingsActivity, - getString(R.string.something_went_wrong_msg), - Toast.LENGTH_SHORT - ).show() } // Added all the onclick event listeners @@ -95,17 +92,17 @@ class SettingsActivity : AppCompatActivity() { } binding.toggleThemeBtn.setOnClickListener { - val sharedPrefs = getSharedPreferences(Constant.APP_PREFS_NAME, MODE_PRIVATE) - val currentThemeStyle = - sharedPrefs.getInt(Constant.THEME_KEY, R.style.PasscodesTheme_Default) + lifecycleScope.launch { + val currentThemeStyle = appDatastore.data.first().theme - val currentIndex = THEMES.indexOf(currentThemeStyle) - val nextIndex = (currentIndex + 1) % THEMES.size - val newThemeStyle = THEMES[nextIndex] + val currentIndex = THEMES.indexOf(currentThemeStyle) + val nextIndex = (currentIndex + 1) % THEMES.size + val newThemeStyle = THEMES[nextIndex] - // Save the new theme and restart the application to apply it - sharedPrefs.edit { putInt(Constant.THEME_KEY, newThemeStyle) } - recreate() + appDatastore.updateData { it.copy(theme = newThemeStyle) } + + recreate() + } Toast.makeText( this@SettingsActivity, diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/UpdatePasswordActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/UpdatePasswordActivity.kt index 4824b8f6..901c3f09 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/UpdatePasswordActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/UpdatePasswordActivity.kt @@ -7,8 +7,10 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivityUpdatePasswordBinding -import com.jeeldobariya.passcodes.utils.CommonUtils +import com.jeeldobariya.passcodes.utils.appDatastore import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import org.koin.androidx.viewmodel.ext.android.viewModel @@ -22,7 +24,9 @@ class UpdatePasswordActivity : AppCompatActivity() { private lateinit var binding: ActivityUpdatePasswordBinding override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivityUpdatePasswordBinding.inflate(layoutInflater) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/ViewPasswordActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/ViewPasswordActivity.kt index 6244bcd5..8d1ae41f 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/ViewPasswordActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/ViewPasswordActivity.kt @@ -10,8 +10,9 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import com.jeeldobariya.passcodes.R import com.jeeldobariya.passcodes.databinding.ActivityViewPasswordBinding -import com.jeeldobariya.passcodes.utils.CommonUtils +import com.jeeldobariya.passcodes.utils.appDatastore import com.jeeldobariya.passcodes.utils.collectLatestLifecycleFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import org.koin.androidx.viewmodel.ext.android.viewModel @@ -26,7 +27,9 @@ class ViewPasswordActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { - CommonUtils.updateCurrTheme(this) + runBlocking { + setTheme(appDatastore.data.first().theme) + } super.onCreate(savedInstanceState) binding = ActivityViewPasswordBinding.inflate(layoutInflater) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/CommonUtils.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/CommonUtils.kt deleted file mode 100644 index e5d7f238..00000000 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/CommonUtils.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.jeeldobariya.passcodes.utils - -import android.content.Context -import android.content.Context.MODE_PRIVATE -import com.jeeldobariya.passcodes.R - -class CommonUtils { - companion object { - fun getCurrTheme(context: Context): Int { - val sharedPrefs = context.getSharedPreferences(Constant.APP_PREFS_NAME, MODE_PRIVATE) - val savedThemeStyle = - sharedPrefs.getInt(Constant.THEME_KEY, R.style.PasscodesTheme_Default) - return savedThemeStyle - } - - fun updateCurrTheme(context: Context) { - context.setTheme(getCurrTheme(context.applicationContext)) - } - } -} From 50a32e3e30ec10316599e11e00847dba4ba071b5 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 21 Nov 2025 11:37:59 +0530 Subject: [PATCH 16/21] chore: unverified solution for data store migration.... --- .../passcodes/flags/FeatureFlagsSettings.kt | 84 ++++++++++++++++++- .../passcodes/utils/AppSettings.kt | 2 + 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt index 88860158..f1d288c1 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt @@ -1,13 +1,95 @@ package com.jeeldobariya.passcodes.flags +// This file contains a solution as commented code... ignore it.. if you don't entertain it. + + import android.content.Context +// import androidx.datastore.core.DataMigration import androidx.datastore.dataStore import kotlinx.serialization.Serializable -val Context.featureFlagsDatastore by dataStore(fileName = "feature-flags-settings-v1.json", serializer = FeatureFlagsSettingsSerializer) +val Context.featureFlagsDatastore by dataStore( + fileName = "feature-flags-settings-v1.json", + serializer = FeatureFlagsSettingsSerializer, + // produceMigrations = { listOf(DataStoreMigration1_2) } +) @Serializable data class FeatureFlagsSettings( + val version: Int = 1, val isPreviewFeaturesEnabled: Boolean = false, val isPreviewLayoutEnabled: Boolean = false ) + +/* +Let say we have added a new feature flag, for custom backends.. +like this in Feature Flag Settings. + +```kotlin +@Serializable +data class FeatureFlagsSettings( + val version: Int = 2, + val isPreviewFeaturesEnabled: Boolean = false, + val isPreviewLayoutEnabled: Boolean = false, + val isCustomBackendFeatureEnabled: Boolean = false, +) +``` + +Then we can create a migration like this, and data will be migrated + +```kotlin +data object DataStoreMigration1_2: DataMigration { + override suspend fun cleanUp() { + // I don't think this is need in our case (according to rules written below..) + TODO("Not yet implemented") + } + + override suspend fun migrate(currentData: FeatureFlagsSettings): FeatureFlagsSettings { + return FeatureFlagsSettings( + // this is previous version flags this will be need to restore users current data. + isPreviewFeaturesEnabled = currentData.isPreviewFeaturesEnabled, + isPreviewLayoutEnabled = currentData.isPreviewLayoutEnabled, + + // this is new flag has already have default value, but we will explicitly declare it for clarity reasons.... + isCustomBackendFeatureEnabled = false + + // [!WARNING] + // this should not restore version field from current data.... + // because if we do `version = currentData.version` then it will break the system in next run of migrations. + ) + } + + override suspend fun shouldMigrate(currentData: FeatureFlagsSettings): Boolean { + return currentData.version < 2 + } +} +``` + +## Conclusion: + +I don't know weather this will work or not... let say it will.. +we will eventually find out... + +Here I am just proposing the solution that work perfectly in my mind.. +I have not tested this solution nor do, I have seen this anywhere so I don't know weather this work or not.. +But here are some links that I have refer to, while coming up with the solution... + +- https://medium.com/androiddevelopers/datastore-and-data-migration-fdca806eb1aa +- https://stackoverflow.com/questions/69457920/how-to-perform-version-migrations-in-android-jetpack-datastore +- https://github.com/yogeshpaliyal/KeyPass/blob/master/common/src/main/java/com/yogeshpaliyal/common/utils/SharedPreferenceUtils.kt +- https://github.com/PasscodesApp/Passcodes/pull/52 + +they all use preferenceDataStore. which i don;t entertain using... because i guess it too complex.. + +### Rules (Assumptions): + +- To this solution to work we can only add the new field... +- we can't change existing field nor do we can change it's datatype. +- we need to provide the default value to each and every field... +- we can only extend it can;t modify it.... + +**Main Assumption**: the under-lying datastore androidx library, will pass the currentData in `migrate()` function.. +with old field restore and new field will have default value. + +I think for this use case, we won;t need to modify field, so this solution work here.. +*/ diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt index 7d3edf5d..30980122 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt @@ -1,5 +1,7 @@ package com.jeeldobariya.passcodes.utils +// please refer to `app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt` for Migration Guide. + import android.content.Context import androidx.datastore.dataStore import com.jeeldobariya.passcodes.R From fc77f01c9f07a33f23fa15377b42c40978355ebc Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 21 Nov 2025 11:40:24 +0530 Subject: [PATCH 17/21] feat: change datastore file name --- .../com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt | 2 +- .../main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt index f1d288c1..28a6cea4 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/flags/FeatureFlagsSettings.kt @@ -9,7 +9,7 @@ import androidx.datastore.dataStore import kotlinx.serialization.Serializable val Context.featureFlagsDatastore by dataStore( - fileName = "feature-flags-settings-v1.json", + fileName = "feature-flags-settings.json", serializer = FeatureFlagsSettingsSerializer, // produceMigrations = { listOf(DataStoreMigration1_2) } ) diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt index 30980122..ec392d03 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/utils/AppSettings.kt @@ -7,7 +7,7 @@ import androidx.datastore.dataStore import com.jeeldobariya.passcodes.R import kotlinx.serialization.Serializable -val Context.appDatastore by dataStore(fileName = "app-settings-v1.json", serializer = AppSettingsSerializer) +val Context.appDatastore by dataStore(fileName = "app-settings.json", serializer = AppSettingsSerializer) @Serializable data class AppSettings( From 49fa7cba9319df08a34213fb1f05f86c9cb3a716 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 21 Nov 2025 11:42:53 +0530 Subject: [PATCH 18/21] feat: prepare for unofficial release in telegram community --- app/build.gradle.kts | 2 +- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fd398410..228f01a3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -29,7 +29,7 @@ android { minSdk = 26 targetSdk = 34 versionCode = 2 - versionName = "v1.1.2-rc.1" + versionName = "v1.1.2-rc.2" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 52971db0..fd9d9e28 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ Passcodes - v1.1.2-rc1 + v1.1.2-rc2 Developed by: Dobariya Jeel From ae5cebafe2fedec351487d43ca6cabbf7a6354df Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 21 Nov 2025 11:57:19 +0530 Subject: [PATCH 19/21] fix: icons of staging & debug build --- app/build.gradle.kts | 4 ++-- app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher.xml | 1 + app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher_round.xml | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 228f01a3..91cd641c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -109,7 +109,7 @@ android { isShrinkResources = false isMinifyEnabled = false - manifestPlaceholders["appIcon"] = "@drawable/dev_ic_launcher_foreground" + manifestPlaceholders["appIcon"] = "@mipmap/dev_ic_launcher" manifestPlaceholders["appLabel"] = "Passcodes-Dev" } @@ -129,7 +129,7 @@ android { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") - manifestPlaceholders["appIcon"] = "@drawable/dev_ic_launcher_foreground" + manifestPlaceholders["appIcon"] = "@mipmap/dev_ic_launcher" manifestPlaceholders["appLabel"] = "Passcodes-Staging" } } diff --git a/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher.xml index 9c155d17..b287e472 100644 --- a/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher.xml @@ -2,4 +2,5 @@ + diff --git a/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher_round.xml index 9c155d17..b287e472 100644 --- a/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/dev_ic_launcher_round.xml @@ -2,4 +2,5 @@ + From 3b4c196e2a15f84411a5873fad958628096511d3 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 21 Nov 2025 12:03:46 +0530 Subject: [PATCH 20/21] chore: Add a shared git hooks --- .githooks/pre-commit | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..e69de29b From ccd20dd117b80ec045a915a2020d0ddca44a1c19 Mon Sep 17 00:00:00 2001 From: Jeel Dobariya Date: Fri, 21 Nov 2025 12:11:02 +0530 Subject: [PATCH 21/21] feat: add conventional git commit hook --- .githooks/commit-msg | 47 ++++++++++++++++++++++++++++++++++++++++++++ .githooks/pre-commit | 0 2 files changed, 47 insertions(+) create mode 100755 .githooks/commit-msg delete mode 100755 .githooks/pre-commit diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 00000000..6a0c147f --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +# Path to the commit message file (provided by Git). +COMMIT_MSG_FILE=$1 + +# Ignore automatic commit messages containing ' into ' or 'Merge'. +if grep --quiet --extended-regexp " into |^Merge " "$COMMIT_MSG_FILE"; then + exit 0 +fi + +# Read the commit message from the file. +COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") + +CONVENTIONAL_COMMIT_REGEX='^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\([a-z0-9_.-]+\))?(!)?:\s.*$' + +# Check if the commit message matches the regex. +if ! [[ $COMMIT_MSG =~ $CONVENTIONAL_COMMIT_REGEX ]]; then + echo "ERROR: Commit message does not follow Conventional Commits format." + echo + echo "The commit message should be structured as follows:" + echo "(): " + echo "[optional body]" + echo "[optional footer(s)]" + echo + echo "Valid types are:" + echo " feat: A new feature." + echo " fix: A bug fix." + echo " docs: Documentation changes." + echo " style: Code style changes (formatting, missing semicolons, etc.)." + echo " refactor: Code refactoring (neither fixes a bug nor adds a feature)." + echo " test: Adding or updating tests." + echo " chore: Routine tasks like updating dependencies or build tools." + echo " build: Changes affecting the build system or external dependencies." + echo " ci: Changes to CI configuration files or scripts." + echo " perf: Performance improvements." + echo " revert: Reverting a previous commit." + echo + echo "Examples:" + echo " feat(auth): add login functionality" + echo " fix(api)!: resolve timeout issue" + echo " docs(readme): update installation instructions" + echo + exit 1 +fi + +exit 0 + diff --git a/.githooks/pre-commit b/.githooks/pre-commit deleted file mode 100755 index e69de29b..00000000