From 90243ab19e9f2c3e71f2f16071e7343651c3cfab Mon Sep 17 00:00:00 2001 From: polodarb Date: Sun, 17 Sep 2023 23:55:35 +0300 Subject: [PATCH 01/24] Fixed data clear in play store --- .../ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt | 3 ++- .../gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt | 3 ++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt index 1daea1b0..341e9be2 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt @@ -1,5 +1,6 @@ package ua.polodarb.gmsflags.ui.screens.flagChangeScreen +import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel @@ -305,7 +306,7 @@ class FlagChangeScreenViewModel( CoroutineScope(Dispatchers.IO).launch { Shell.cmd("am force-stop $androidPkgName").exec() Shell.cmd("rm -rf /data/data/$androidPkgName/files/phenotype").exec() - if (pkgName == "com.android.vending") { + if (pkgName.contains("finsky") || pkgName.contains("vending")) { Shell.cmd("rm -rf /data/data/com.android.vending/files/experiment*").exec() Shell.cmd("am force-stop com.android.vending").exec() } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index c757f190..97f98a53 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -40,6 +40,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import org.koin.androidx.compose.koinViewModel @@ -187,7 +188,7 @@ fun SuggestedFlagItem( ) { ListItem( headlineContent = { Text(flagName) }, - supportingContent = { Text(senderName) }, + supportingContent = { Text(stringResource(R.string.finder) + senderName) }, trailingContent = { Row { Switch( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e03924b7..db803a9d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -39,4 +39,5 @@ Update app to v Close Update GMS Flags + "Finder: " \ No newline at end of file From 91441be0e568bee6c7d5bd18de4e071716b2efb9 Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 19 Sep 2023 14:46:44 +0300 Subject: [PATCH 02/24] Implemented basic realization of roomDB for saved packages --- app/build.gradle.kts | 5 ++++ .../data/databases/local/AppDatabase.kt | 13 ++++++++++ .../data/databases/local/dao/PackagesDAO.kt | 25 +++++++++++++++++++ .../databases/local/enities/SavedPackages.kt | 9 +++++++ 4 files changed, 52 insertions(+) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e31f3ad7..bb444112 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -54,6 +54,11 @@ android { dependencies { + // Room Database + val roomVersion = "2.5.1" + implementation("androidx.room:room-runtime:$roomVersion") + annotationProcessor("androidx.room:room-compiler:$roomVersion") + // KTOR val ktorVersion = "2.3.4" implementation("io.ktor:ktor-client-core:$ktorVersion") diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt new file mode 100644 index 00000000..1d694808 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt @@ -0,0 +1,13 @@ +package ua.polodarb.gmsflags.data.databases.local + +import androidx.room.Database +import androidx.room.RoomDatabase +import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO +import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages + +@Database(entities = [SavedPackages::class], version = 1) +abstract class AppDatabase: RoomDatabase() { + + abstract fun packagesDao(): PackagesDAO + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt new file mode 100644 index 00000000..c56083e9 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt @@ -0,0 +1,25 @@ +package ua.polodarb.gmsflags.data.databases.local.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages + +@Dao +interface PackagesDAO { + + @Query("SELECT * FROM saved_packages") + fun getSavedPackages(): List + + @Insert(entity = SavedPackages::class, onConflict = OnConflictStrategy.REPLACE) + fun savePackage(pkgName: String) + + @Query("DELETE FROM saved_packages WHERE pkg_name = :pkgName") + fun deleteSavedPackage(pkgName: String) + + @Query("DELETE FROM saved_packages") + fun deleteAllSavedPackages() + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt new file mode 100644 index 00000000..91baec13 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt @@ -0,0 +1,9 @@ +package ua.polodarb.gmsflags.data.databases.local.enities + +import androidx.room.ColumnInfo +import androidx.room.Entity + +@Entity(tableName = "saved_packages") +data class SavedPackages( + @ColumnInfo(name = "pkg_name") val pkgName: String? +) \ No newline at end of file From d09e3cf8b42926f08910da3e116c6d329237b3d4 Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 19 Sep 2023 14:59:40 +0300 Subject: [PATCH 03/24] Implemented database creation via Koin DI --- .../ua/polodarb/gmsflags/GMSApplication.kt | 3 ++- .../java/ua/polodarb/gmsflags/di/AppModule.kt | 2 ++ .../ua/polodarb/gmsflags/di/DatabaseModule.kt | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt diff --git a/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt b/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt index 545727cc..ab54166e 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt @@ -17,6 +17,7 @@ import org.koin.core.context.startKoin import org.koin.core.logger.Level import ua.polodarb.gmsflags.data.databases.gms.RootDatabase import ua.polodarb.gmsflags.di.appModule +import ua.polodarb.gmsflags.di.databaseModule import ua.polodarb.gmsflags.di.viewModelsModule import ua.polodarb.gmsflags.ui.CrashActivity import ua.polodarb.gmsflags.ui.ExceptionHandler @@ -52,7 +53,7 @@ class GMSApplication : Application() { startKoin { androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.NONE) androidContext(this@GMSApplication) - modules(listOf(appModule, viewModelsModule)) + modules(listOf(appModule, viewModelsModule, databaseModule)) } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt index beb7c949..e91e2346 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt @@ -6,6 +6,7 @@ import ua.polodarb.gmsflags.data.repo.AppsListRepository import ua.polodarb.gmsflags.data.repo.DatabaseRepository val appModule = module { + single { androidApplication().applicationContext } @@ -21,4 +22,5 @@ val appModule = module { context = get() ) } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt new file mode 100644 index 00000000..270ff2de --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt @@ -0,0 +1,24 @@ +package ua.polodarb.gmsflags.di + +import androidx.room.Room +import org.koin.android.ext.koin.androidApplication +import org.koin.dsl.module +import ua.polodarb.gmsflags.data.databases.local.AppDatabase +import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO + +val databaseModule = module { + + single { + Room.databaseBuilder( + androidApplication().applicationContext, + AppDatabase::class.java, + "gms_flags_database" + ).build() + } + + single { + val database = get() + database.packagesDao() + } + +} \ No newline at end of file From 1b07a9577863fa695fb2f3dcccf550eb5cda7b56 Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 19 Sep 2023 22:09:59 +0300 Subject: [PATCH 04/24] Implemented saving and deleting packages in database --- app/build.gradle.kts | 6 +- .../ua/polodarb/gmsflags/GMSApplication.kt | 3 +- .../data/databases/local/dao/PackagesDAO.kt | 8 +- .../databases/local/enities/SavedPackages.kt | 3 +- ...tabaseRepository.kt => GmsDBRepository.kt} | 3 +- .../gmsflags/data/repo/RoomDBRepository.kt | 26 +++++++ .../java/ua/polodarb/gmsflags/di/AppModule.kt | 14 +--- .../ua/polodarb/gmsflags/di/DatabaseModule.kt | 2 +- .../polodarb/gmsflags/di/RepositoryModule.kt | 28 +++++++ .../polodarb/gmsflags/di/ViewModelsModule.kt | 12 ++- .../FlagChangeScreenViewModel.kt | 5 +- .../screens/packagesScreen/PackagesScreen.kt | 44 ++++------- .../packagesScreen/PackagesScreenViewModel.kt | 53 ++++++++++++- .../savedScreen/SavedPackagesScreen.kt | 77 +++++++++++++++++-- .../ui/screens/savedScreen/SavedScreen.kt | 13 +++- .../savedScreen/SavedScreenViewModel.kt | 44 +++++++++++ .../SuggestionScreenViewModel.kt | 14 ++-- 17 files changed, 281 insertions(+), 74 deletions(-) rename app/src/main/java/ua/polodarb/gmsflags/data/repo/{DatabaseRepository.kt => GmsDBRepository.kt} (98%) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bb444112..4155b4af 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("org.jetbrains.kotlin.android") id("com.google.devtools.ksp") id("org.jetbrains.kotlin.plugin.serialization") +// id("kotlin-kapt") } android { @@ -55,9 +56,10 @@ android { dependencies { // Room Database - val roomVersion = "2.5.1" + val roomVersion = "2.5.2" implementation("androidx.room:room-runtime:$roomVersion") - annotationProcessor("androidx.room:room-compiler:$roomVersion") + ksp("androidx.room:room-compiler:$roomVersion") + implementation("androidx.room:room-ktx:$roomVersion") // KTOR val ktorVersion = "2.3.4" diff --git a/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt b/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt index ab54166e..4ad88167 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/GMSApplication.kt @@ -18,6 +18,7 @@ import org.koin.core.logger.Level import ua.polodarb.gmsflags.data.databases.gms.RootDatabase import ua.polodarb.gmsflags.di.appModule import ua.polodarb.gmsflags.di.databaseModule +import ua.polodarb.gmsflags.di.repositoryModule import ua.polodarb.gmsflags.di.viewModelsModule import ua.polodarb.gmsflags.ui.CrashActivity import ua.polodarb.gmsflags.ui.ExceptionHandler @@ -53,7 +54,7 @@ class GMSApplication : Application() { startKoin { androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.NONE) androidContext(this@GMSApplication) - modules(listOf(appModule, viewModelsModule, databaseModule)) + modules(listOf(appModule, viewModelsModule, databaseModule, repositoryModule)) } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt index c56083e9..0479a447 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt @@ -1,23 +1,23 @@ package ua.polodarb.gmsflags.data.databases.local.dao import androidx.room.Dao -import androidx.room.Delete import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query +import kotlinx.coroutines.flow.Flow import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages @Dao interface PackagesDAO { @Query("SELECT * FROM saved_packages") - fun getSavedPackages(): List + fun getSavedPackages(): Flow> @Insert(entity = SavedPackages::class, onConflict = OnConflictStrategy.REPLACE) - fun savePackage(pkgName: String) + suspend fun savePackage(pkgName: SavedPackages) @Query("DELETE FROM saved_packages WHERE pkg_name = :pkgName") - fun deleteSavedPackage(pkgName: String) + suspend fun deleteSavedPackage(pkgName: String) @Query("DELETE FROM saved_packages") fun deleteAllSavedPackages() diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt index 91baec13..6ddff24b 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedPackages.kt @@ -2,8 +2,9 @@ package ua.polodarb.gmsflags.data.databases.local.enities import androidx.room.ColumnInfo import androidx.room.Entity +import androidx.room.PrimaryKey @Entity(tableName = "saved_packages") data class SavedPackages( - @ColumnInfo(name = "pkg_name") val pkgName: String? + @PrimaryKey @ColumnInfo(name = "pkg_name") val pkgName: String ) \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/repo/DatabaseRepository.kt b/app/src/main/java/ua/polodarb/gmsflags/data/repo/GmsDBRepository.kt similarity index 98% rename from app/src/main/java/ua/polodarb/gmsflags/data/repo/DatabaseRepository.kt rename to app/src/main/java/ua/polodarb/gmsflags/data/repo/GmsDBRepository.kt index e6911c97..1b221d04 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/repo/DatabaseRepository.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/repo/GmsDBRepository.kt @@ -1,14 +1,13 @@ package ua.polodarb.gmsflags.data.repo import android.content.Context -import android.util.Log import kotlinx.coroutines.delay import kotlinx.coroutines.flow.flow import ua.polodarb.gmsflags.GMSApplication import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.FlagChangeUiStates import ua.polodarb.gmsflags.ui.screens.packagesScreen.ScreenUiStates -class DatabaseRepository( +class GmsDBRepository( private val context: Context ) { diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt b/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt new file mode 100644 index 00000000..16381956 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt @@ -0,0 +1,26 @@ +package ua.polodarb.gmsflags.data.repo + +import android.util.Log +import kotlinx.coroutines.flow.flow +import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO +import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages + +class RoomDBRepository( + private val savedPackagesDao: PackagesDAO +) { + + suspend fun getSavedPackages() = flow> { + savedPackagesDao.getSavedPackages().collect { + emit(it) + } + } + + suspend fun deleteSavedPackage(pkgName: String) { + savedPackagesDao.deleteSavedPackage(pkgName) + } + + suspend fun savePackage(pkgName: String) { + savedPackagesDao.savePackage(SavedPackages(pkgName)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt index e91e2346..48e97163 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/AppModule.kt @@ -3,7 +3,7 @@ package ua.polodarb.gmsflags.di import org.koin.android.ext.koin.androidApplication import org.koin.dsl.module import ua.polodarb.gmsflags.data.repo.AppsListRepository -import ua.polodarb.gmsflags.data.repo.DatabaseRepository +import ua.polodarb.gmsflags.data.repo.GmsDBRepository val appModule = module { @@ -11,16 +11,4 @@ val appModule = module { androidApplication().applicationContext } - single { - DatabaseRepository( - context = get() - ) - } - - single { - AppsListRepository( - context = get() - ) - } - } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt index 270ff2de..2f95a875 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt @@ -8,7 +8,7 @@ import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO val databaseModule = module { - single { + single { Room.databaseBuilder( androidApplication().applicationContext, AppDatabase::class.java, diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt new file mode 100644 index 00000000..2cfdecca --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt @@ -0,0 +1,28 @@ +package ua.polodarb.gmsflags.di + +import org.koin.dsl.module +import ua.polodarb.gmsflags.data.repo.AppsListRepository +import ua.polodarb.gmsflags.data.repo.GmsDBRepository +import ua.polodarb.gmsflags.data.repo.RoomDBRepository + +val repositoryModule = module { + + single { + GmsDBRepository( + context = get() + ) + } + + single { + AppsListRepository( + context = get() + ) + } + + single { + RoomDBRepository( + savedPackagesDao = get() + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt index bce4abab..b832a34f 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt @@ -5,12 +5,15 @@ import org.koin.dsl.module import ua.polodarb.gmsflags.ui.screens.appsScreen.AppsScreenViewModel import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.FlagChangeScreenViewModel import ua.polodarb.gmsflags.ui.screens.packagesScreen.PackagesScreenViewModel +import ua.polodarb.gmsflags.ui.screens.savedScreen.SavedScreenViewModel import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionScreenViewModel val viewModelsModule = module { + viewModel { PackagesScreenViewModel( - repository = get() + gmsRepository = get(), + roomRepository = get() ) } @@ -32,4 +35,11 @@ val viewModelsModule = module { repository = get() ) } + + viewModel { + SavedScreenViewModel( + roomRepository = get() + ) + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt index 341e9be2..f1a9e00c 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt @@ -1,6 +1,5 @@ package ua.polodarb.gmsflags.ui.screens.flagChangeScreen -import android.util.Log import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel @@ -13,11 +12,11 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import ua.polodarb.gmsflags.data.repo.DatabaseRepository +import ua.polodarb.gmsflags.data.repo.GmsDBRepository class FlagChangeScreenViewModel( private val pkgName: String, - private val repository: DatabaseRepository + private val repository: GmsDBRepository ) : ViewModel() { private val _stateBoolean = diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreen.kt index d36b2a13..a6ae66f7 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreen.kt @@ -63,6 +63,7 @@ fun PackagesScreen( val viewModel = koinViewModel() val uiState = viewModel.state.collectAsState() + val savedPackagesList = viewModel.stateSavedPackages.collectAsState() val list = remember { mutableStateMapOf() @@ -172,9 +173,12 @@ fun PackagesScreen( list.putAll((uiState.value as ScreenUiStates.Success).data) SuccessListItems( list = filteredListState, + savedPackagesList = savedPackagesList.value, + viewModel = viewModel, onFlagClick = onFlagClick ) } + is ScreenUiStates.Loading -> LoadingProgressBar() is ScreenUiStates.Error -> ErrorLoadScreen() } @@ -185,16 +189,25 @@ fun PackagesScreen( @Composable private fun SuccessListItems( list: Map, + savedPackagesList: List, + viewModel: PackagesScreenViewModel, onFlagClick: (packageName: String) -> Unit ) { - //todo: This code have problems with recompositions - LazyColumn { itemsIndexed(list.toList()) { index, item -> - LazyItem( + PackagesLazyItem( packageName = item.first, packagesCount = item.second.toInt(), + checked = savedPackagesList.contains(item.first), + onCheckedChange = { + if (it) { + viewModel.savePackage(item.first) + } else { + viewModel.deleteSavedPackage(item.first) + } +// viewModel.updateSavedState(item.first) + }, lastItem = index == list.size - 1, modifier = Modifier.clickable { onFlagClick(item.first) @@ -208,30 +221,7 @@ private fun SuccessListItems( } @Composable -fun LazyItem( - modifier: Modifier = Modifier, - packageName: String, - packagesCount: Int, - lastItem: Boolean = false, -) { - var checkedState by rememberSaveable { - mutableStateOf(false) - } - - LazyItem( - packageName = packageName, - packagesCount = packagesCount, - modifier = modifier, - checked = checkedState, - onCheckedChange = { checked -> - checkedState = checked - }, - lastItem = lastItem - ) -} - -@Composable -fun LazyItem( +fun PackagesLazyItem( modifier: Modifier = Modifier, packageName: String, packagesCount: Int, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt index 600c5641..cd5d206c 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt @@ -1,5 +1,6 @@ package ua.polodarb.gmsflags.ui.screens.packagesScreen +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers @@ -8,19 +9,39 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import ua.polodarb.gmsflags.data.repo.DatabaseRepository +import ua.polodarb.gmsflags.data.repo.GmsDBRepository +import ua.polodarb.gmsflags.data.repo.RoomDBRepository +import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionsScreenUiStates class PackagesScreenViewModel( - private val repository: DatabaseRepository + private val gmsRepository: GmsDBRepository, + private val roomRepository: RoomDBRepository, ) : ViewModel() { private val _state = MutableStateFlow(ScreenUiStates.Loading) val state: StateFlow = _state.asStateFlow() + private val _stateSavedPackages = + MutableStateFlow>(emptyList()) + val stateSavedPackages: StateFlow> = _stateSavedPackages.asStateFlow() + init { + initGmsPackagesList() + getAllSavedPackages() + } + +// fun updateSavedState(pkgName: String) { +// val currentState = _stateSavedPackages.value.toMutableList() +// if (currentState.isNotEmpty()) { +// currentState.remove(pkgName) +// _stateSavedPackages.value = currentState.toList() +// } +// } + + fun initGmsPackagesList() { viewModelScope.launch { withContext(Dispatchers.IO) { - repository.getGmsPackages().collect { uiState -> + gmsRepository.getGmsPackages().collect { uiState -> when (uiState) { is ScreenUiStates.Success -> { _state.value = ScreenUiStates.Success(uiState.data) @@ -39,4 +60,30 @@ class PackagesScreenViewModel( } } + private fun getAllSavedPackages() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.getSavedPackages().collect { + _stateSavedPackages.value = it + } + } + } + } + + fun savePackage(pkgName: String) { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.savePackage(pkgName) + } + } + } + + fun deleteSavedPackage(pkgName: String) { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.deleteSavedPackage(pkgName) + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt index 525105e4..e4f0e8e6 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt @@ -1,24 +1,89 @@ package ua.polodarb.gmsflags.ui.screens.savedScreen import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconToggleButton +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import ua.polodarb.gmsflags.ui.screens.packagesScreen.LazyItem +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import ua.polodarb.gmsflags.R @Composable -fun SavedPackagesScreen() { +fun SavedPackagesScreen( + savedPackagesList: List, + viewModel: SavedScreenViewModel +) { + Column( modifier = Modifier.fillMaxSize() ) { LazyColumn { - items(20) { - LazyItem( - packageName = "com.google.android.gms.cast", - packagesCount = 0 + itemsIndexed(savedPackagesList) { index, item -> + SavedPackagesLazyItem( + packageName = item, + checked = savedPackagesList.contains(item), + onCheckedChange = { + if (!it) viewModel.deleteSavedPackage(item) + }, + lastItem = savedPackagesList.size - 1 == index ) } } } } + +@Composable +fun SavedPackagesLazyItem( + modifier: Modifier = Modifier, + packageName: String, + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + lastItem: Boolean, +) { + Column { + Row( + modifier = modifier + .fillMaxWidth() + .padding(vertical = 8.dp), verticalAlignment = Alignment.CenterVertically + ) { + IconToggleButton(checked = checked, onCheckedChange = onCheckedChange) { + if (checked) { + Icon( + painterResource(id = R.drawable.ic_save_active), + contentDescription = null + ) + } else { + Icon( + painterResource(id = R.drawable.ic_save_inactive), + contentDescription = null + ) + } + } + Column(Modifier.weight(0.9f)) { + Text(text = packageName, fontSize = 15.sp) + } + Icon( + modifier = Modifier + .padding(16.dp), + painter = painterResource(id = R.drawable.ic_next), + contentDescription = null + ) + } + } + if (!lastItem) HorizontalDivider(Modifier.padding(horizontal = 16.dp)) +} diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt index b3042cb5..2e59f9fb 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt @@ -38,6 +38,7 @@ import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope @@ -57,8 +58,10 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch +import org.koin.androidx.compose.koinViewModel import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.ui.components.inserts.NotImplementedScreen +import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionScreenViewModel @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable @@ -66,6 +69,10 @@ fun SavedScreen( onSettingsClick: () -> Unit, onPackagesClick: () -> Unit ) { + + val viewModel = koinViewModel() + val savedPackages = viewModel.stateSavedPackages.collectAsState() + val topBarState = rememberTopAppBarState() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(topBarState) val context = LocalContext.current @@ -176,9 +183,11 @@ fun SavedScreen( contentPadding = PaddingValues(top = paddingValues.calculateTopPadding()) ) { page -> when (page) { -// 0 -> SavedPackagesScreen() + 0 -> SavedPackagesScreen( + savedPackagesList = savedPackages.value, + viewModel = viewModel + ) // 1 -> SavedFlagsScreen() - 0 -> NotImplementedScreen() 1 -> NotImplementedScreen() } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt new file mode 100644 index 00000000..1841bf69 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt @@ -0,0 +1,44 @@ +package ua.polodarb.gmsflags.ui.screens.savedScreen + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import ua.polodarb.gmsflags.data.repo.RoomDBRepository +import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionsScreenUiStates + +class SavedScreenViewModel( + val roomRepository: RoomDBRepository +): ViewModel() { + + private val _stateSavedPackages = + MutableStateFlow>(emptyList()) + val stateSavedPackages: StateFlow> = _stateSavedPackages.asStateFlow() + + init { + getAllSavedPackages() + } + + fun getAllSavedPackages() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.getSavedPackages().collect { + _stateSavedPackages.value = it + } + } + } + } + + fun deleteSavedPackage(pkgName: String) { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.deleteSavedPackage(pkgName) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt index 4468d22b..c1b11602 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt @@ -1,6 +1,5 @@ package ua.polodarb.gmsflags.ui.screens.suggestionsScreen -import android.content.Context import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -12,12 +11,11 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import ua.polodarb.gmsflags.GMSApplication -import ua.polodarb.gmsflags.data.repo.DatabaseRepository +import ua.polodarb.gmsflags.data.repo.GmsDBRepository import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.FlagChangeUiStates class SuggestionScreenViewModel( - private val repository: DatabaseRepository + private val repository: GmsDBRepository ) : ViewModel() { private val _stateSuggestionsFlags = @@ -42,12 +40,12 @@ class SuggestionScreenViewModel( } } - fun initUsers() { + private fun initUsers() { usersList.clear() usersList.addAll(repository.getUsers()) } - fun getAllOverriddenBoolFlags() { + private fun getAllOverriddenBoolFlags() { viewModelScope.launch { withContext(Dispatchers.IO) { repository.getAllOverriddenBoolFlags().collect { uiState -> @@ -68,7 +66,7 @@ class SuggestionScreenViewModel( } } - fun updateFlagValues(suggestedFlags: List, flagValuesMap: Map): List { + private fun updateFlagValues(suggestedFlags: List, flagValuesMap: Map): List { val list = suggestedFlags.map { suggestedFlag -> val newFlagValue = flagValuesMap[suggestedFlag.phenotypeFlagName[0]]?.toIntOrNull() == 1 SuggestedFlag( @@ -82,7 +80,7 @@ class SuggestionScreenViewModel( return list } - fun clearPhenotypeCache(pkgName: String) { + private fun clearPhenotypeCache(pkgName: String) { val androidPkgName = repository.androidPackage(pkgName) CoroutineScope(Dispatchers.IO).launch { Shell.cmd("am force-stop $androidPkgName").exec() From d16b73c69569d1659ebc0f0697ccf2c853a59411 Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 19 Sep 2023 22:24:49 +0300 Subject: [PATCH 05/24] Implemented navigation to flags list from saved packages --- .../gmsflags/ui/navigation/AppNavigation.kt | 5 +++++ .../ui/screens/savedScreen/SavedPackagesScreen.kt | 13 ++++++++++--- .../gmsflags/ui/screens/savedScreen/SavedScreen.kt | 6 ++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index 0ed12048..376597f7 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -112,6 +112,11 @@ internal fun BottomBarNavigation( // Navigation realization for BottomBar }, onPackagesClick = { parentNavController.navigate(ScreensDestination.Packages.screenRoute) + }, + onFlagClick = { + parentNavController.navigate( + ScreensDestination.FlagChange.createRoute(Uri.encode(it)) + ) } ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt index e4f0e8e6..1c0a87a8 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt @@ -1,5 +1,6 @@ package ua.polodarb.gmsflags.ui.screens.savedScreen +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -26,13 +27,16 @@ import ua.polodarb.gmsflags.R @Composable fun SavedPackagesScreen( savedPackagesList: List, - viewModel: SavedScreenViewModel + viewModel: SavedScreenViewModel, + onFlagClick: (packageName: String) -> Unit ) { Column( modifier = Modifier.fillMaxSize() ) { - LazyColumn { + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { itemsIndexed(savedPackagesList) { index, item -> SavedPackagesLazyItem( packageName = item, @@ -40,7 +44,10 @@ fun SavedPackagesScreen( onCheckedChange = { if (!it) viewModel.deleteSavedPackage(item) }, - lastItem = savedPackagesList.size - 1 == index + lastItem = savedPackagesList.size - 1 == index, + modifier = Modifier.clickable { + onFlagClick(item) + } ) } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt index 2e59f9fb..c9cf8a91 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt @@ -67,7 +67,8 @@ import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionScreenViewMod @Composable fun SavedScreen( onSettingsClick: () -> Unit, - onPackagesClick: () -> Unit + onPackagesClick: () -> Unit, + onFlagClick: (packageName: String) -> Unit, ) { val viewModel = koinViewModel() @@ -185,7 +186,8 @@ fun SavedScreen( when (page) { 0 -> SavedPackagesScreen( savedPackagesList = savedPackages.value, - viewModel = viewModel + viewModel = viewModel, + onFlagClick = onFlagClick ) // 1 -> SavedFlagsScreen() 1 -> NotImplementedScreen() From f8e39b8b2520d0cf3cc3df0bb1c9169b3c41679f Mon Sep 17 00:00:00 2001 From: polodarb Date: Sun, 24 Sep 2023 23:09:51 +0300 Subject: [PATCH 06/24] Implemented entity for saving flags --- .../data/databases/local/AppDatabase.kt | 6 +- .../data/databases/local/dao/FlagsDAO.kt | 25 +++++++ .../data/databases/local/dao/PackagesDAO.kt | 2 +- .../databases/local/enities/SavedFlags.kt | 11 ++++ .../ui/navigation/RootAppNavigation.kt | 3 +- .../screens/settingsScreen/SettingsScreen.kt | 65 +++++++++++++++++++ 6 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt index 1d694808..612c4628 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/AppDatabase.kt @@ -2,12 +2,16 @@ package ua.polodarb.gmsflags.data.databases.local import androidx.room.Database import androidx.room.RoomDatabase +import ua.polodarb.gmsflags.data.databases.local.dao.FlagsDAO import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages -@Database(entities = [SavedPackages::class], version = 1) +@Database(entities = [SavedPackages::class, SavedFlags::class], version = 1) abstract class AppDatabase: RoomDatabase() { abstract fun packagesDao(): PackagesDAO + abstract fun flagsDao(): FlagsDAO + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt new file mode 100644 index 00000000..81c16299 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt @@ -0,0 +1,25 @@ +package ua.polodarb.gmsflags.data.databases.local.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import kotlinx.coroutines.flow.Flow +import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages + +@Dao +interface FlagsDAO { + + @Query("SELECT * FROM saved_packages") + fun getSavedFlags(): Flow> + + @Insert(entity = SavedPackages::class, onConflict = OnConflictStrategy.REPLACE) + suspend fun saveFlag(flagName: SavedPackages) + + @Query("DELETE FROM saved_packages WHERE pkg_name = :flagName") + suspend fun deleteSavedFlag(flagName: String) + + @Query("DELETE FROM saved_packages") + fun deleteAllSavedFlags() + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt index 0479a447..cfe25801 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages @Dao -interface PackagesDAO { +interface PackagesDAO { // todo @Query("SELECT * FROM saved_packages") fun getSavedPackages(): Flow> diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt new file mode 100644 index 00000000..b73a5ebf --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt @@ -0,0 +1,11 @@ +package ua.polodarb.gmsflags.data.databases.local.enities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "saved_flags") +data class SavedFlags( + @PrimaryKey @ColumnInfo(name = "pkg_name") val pkgName: String, + @ColumnInfo(name = "flag_name") val flagName: String +) \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt index 38665264..fbb6e4f8 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt @@ -99,7 +99,8 @@ internal fun RootAppNavigation( NavHost( navController = navController, - startDestination = if (isFirstStart) ScreensDestination.Welcome.screenRoute else ScreensDestination.Root.screenRoute, +// startDestination = if (isFirstStart) ScreensDestination.Welcome.screenRoute else ScreensDestination.Root.screenRoute, + startDestination = ScreensDestination.Settings.screenRoute, modifier = modifier ) { composable( diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt index a5a868d7..9a34ac8b 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt @@ -1,22 +1,36 @@ package ua.polodarb.gmsflags.ui.screens.settingsScreen import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.foundation.selection.toggleable import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp import ua.polodarb.gmsflags.ui.components.inserts.NotImplementedScreen @OptIn(ExperimentalMaterial3Api::class) @@ -56,7 +70,58 @@ fun SettingsScreen( Column(modifier = Modifier.padding(it)) { Column { NotImplementedScreen() +// SettingsContent() } } } +} + +@Composable +fun SettingsContent() { + + val (checkedState, onStateChange) = remember { mutableStateOf(true) } + val list = listOf("Google Services", "Google Play Store") + + list.forEach { + Row( + Modifier + .fillMaxWidth() + .height(56.dp) + .toggleable( + value = checkedState, + onValueChange = { onStateChange(!checkedState) }, + role = Role.Checkbox + ) + .padding(horizontal = 16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = checkedState, + onCheckedChange = null // null recommended for accessibility with screenreaders + ) + Text( + text = it, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(start = 16.dp) + ) + } + } +} + +@Composable +fun SettingsLabel( + text: String +) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(24.dp) + ) { + Text( + text = text, + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(start = 16.dp) + ) + } } \ No newline at end of file From 37f1465b0ddb40db21d0a9ea4d14c2684247419b Mon Sep 17 00:00:00 2001 From: polodarb Date: Sun, 24 Sep 2023 23:39:45 +0300 Subject: [PATCH 07/24] Changed tables for requests in DAO --- .../gmsflags/data/databases/local/dao/FlagsDAO.kt | 11 ++++++----- .../gmsflags/data/databases/local/dao/PackagesDAO.kt | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt index 81c16299..d289b209 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/FlagsDAO.kt @@ -5,21 +5,22 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import kotlinx.coroutines.flow.Flow +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages @Dao interface FlagsDAO { - @Query("SELECT * FROM saved_packages") + @Query("SELECT * FROM saved_flags") fun getSavedFlags(): Flow> - @Insert(entity = SavedPackages::class, onConflict = OnConflictStrategy.REPLACE) - suspend fun saveFlag(flagName: SavedPackages) + @Insert(entity = SavedFlags::class, onConflict = OnConflictStrategy.REPLACE) + suspend fun saveFlag(flagName: SavedFlags) - @Query("DELETE FROM saved_packages WHERE pkg_name = :flagName") + @Query("DELETE FROM saved_flags WHERE flag_name = :flagName") suspend fun deleteSavedFlag(flagName: String) - @Query("DELETE FROM saved_packages") + @Query("DELETE FROM saved_flags") fun deleteAllSavedFlags() } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt index cfe25801..0479a447 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/dao/PackagesDAO.kt @@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages @Dao -interface PackagesDAO { // todo +interface PackagesDAO { @Query("SELECT * FROM saved_packages") fun getSavedPackages(): Flow> From 37216a2f2e84bd6348dc72b6366369373a3a0707 Mon Sep 17 00:00:00 2001 From: polodarb Date: Mon, 25 Sep 2023 02:23:02 +0300 Subject: [PATCH 08/24] Partially implemented the logic of saving flags --- app/src/main/AndroidManifest.xml | 2 +- .../data/databases/local/AppDatabase.kt | 8 +- .../data/databases/local/dao/FlagsDAO.kt | 6 +- .../databases/local/enities/SavedFlags.kt | 3 +- .../gmsflags/data/repo/RoomDBRepository.kt | 19 ++++- .../ua/polodarb/gmsflags/di/DatabaseModule.kt | 6 ++ .../polodarb/gmsflags/di/RepositoryModule.kt | 3 +- .../ua/polodarb/gmsflags/ui/MainActivity.kt | 4 + .../gmsflags/ui/navigation/AppNavigation.kt | 5 +- .../ui/navigation/RootAppNavigation.kt | 3 +- .../flagChangeScreen/FlagChangeScreen.kt | 8 +- .../flagChangeScreen/FlagsItemTypes.kt | 22 ++--- .../screens/savedScreen/SavedFlagsScreen.kt | 82 ++++++++++--------- .../savedScreen/SavedPackagesScreen.kt | 4 +- .../ui/screens/savedScreen/SavedScreen.kt | 13 ++- .../savedScreen/SavedScreenViewModel.kt | 27 +++++- 16 files changed, 141 insertions(+), 74 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3be3f792..32272ef9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ > + fun getSavedFlags(): Flow> @Insert(entity = SavedFlags::class, onConflict = OnConflictStrategy.REPLACE) suspend fun saveFlag(flagName: SavedFlags) - @Query("DELETE FROM saved_flags WHERE flag_name = :flagName") - suspend fun deleteSavedFlag(flagName: String) + @Query("DELETE FROM saved_flags WHERE flag_name = :flagName AND pkg_name = :pkgName") + suspend fun deleteSavedFlag(flagName: String, pkgName: String) @Query("DELETE FROM saved_flags") fun deleteAllSavedFlags() diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt index b73a5ebf..0645d85f 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt @@ -7,5 +7,6 @@ import androidx.room.PrimaryKey @Entity(tableName = "saved_flags") data class SavedFlags( @PrimaryKey @ColumnInfo(name = "pkg_name") val pkgName: String, - @ColumnInfo(name = "flag_name") val flagName: String + @ColumnInfo(name = "flag_name") val flagName: String, + @ColumnInfo(name = "flag_type") val type: String ) \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt b/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt index 16381956..a1af7324 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/repo/RoomDBRepository.kt @@ -2,11 +2,14 @@ package ua.polodarb.gmsflags.data.repo import android.util.Log import kotlinx.coroutines.flow.flow +import ua.polodarb.gmsflags.data.databases.local.dao.FlagsDAO import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.data.databases.local.enities.SavedPackages class RoomDBRepository( - private val savedPackagesDao: PackagesDAO + private val savedPackagesDao: PackagesDAO, + private val savedFlagsDao: FlagsDAO ) { suspend fun getSavedPackages() = flow> { @@ -23,4 +26,18 @@ class RoomDBRepository( savedPackagesDao.savePackage(SavedPackages(pkgName)) } + suspend fun getSavedFlags() = flow { + savedFlagsDao.getSavedFlags().collect { + emit(it) + } + } + + suspend fun deleteSavedFlag(flagName: String, pkgName: String) { + savedFlagsDao.deleteSavedFlag(flagName, pkgName) + } + + suspend fun saveFlag(flagName: String, pkgName: String, flagType: String) { + savedFlagsDao.saveFlag(SavedFlags(pkgName, flagName, flagType)) + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt index 2f95a875..68dc000c 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/DatabaseModule.kt @@ -4,6 +4,7 @@ import androidx.room.Room import org.koin.android.ext.koin.androidApplication import org.koin.dsl.module import ua.polodarb.gmsflags.data.databases.local.AppDatabase +import ua.polodarb.gmsflags.data.databases.local.dao.FlagsDAO import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO val databaseModule = module { @@ -21,4 +22,9 @@ val databaseModule = module { database.packagesDao() } + single { + val database = get() + database.flagsDao() + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt index 2cfdecca..c9357114 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt @@ -21,7 +21,8 @@ val repositoryModule = module { single { RoomDBRepository( - savedPackagesDao = get() + savedPackagesDao = get(), + savedFlagsDao = get() ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/MainActivity.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/MainActivity.kt index 2af01066..75330d6e 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/MainActivity.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/MainActivity.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Bundle import android.view.ViewGroup import android.widget.FrameLayout +import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize @@ -20,6 +21,7 @@ import ua.polodarb.gmsflags.ui.theme.GMSFlagsTheme import java.io.File class MainActivity : ComponentActivity() { + private val appContext = get() as GMSApplication private val configuredFilePath = @@ -41,6 +43,8 @@ class MainActivity : ComponentActivity() { WindowCompat.setDecorFitsSystemWindows(window, false) +// Toast.makeText(this, "$isFirstStart", Toast.LENGTH_SHORT).show() + setContent { GMSFlagsTheme { Surface( diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index 376597f7..69c74fb0 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -113,10 +113,13 @@ internal fun BottomBarNavigation( // Navigation realization for BottomBar onPackagesClick = { parentNavController.navigate(ScreensDestination.Packages.screenRoute) }, - onFlagClick = { + onSavedPackageClick = { parentNavController.navigate( ScreensDestination.FlagChange.createRoute(Uri.encode(it)) ) + }, + onSavedFlagClick = { packageName, flagName -> + // TODO: Implement navigation to flags list } ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt index fbb6e4f8..38665264 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt @@ -99,8 +99,7 @@ internal fun RootAppNavigation( NavHost( navController = navController, -// startDestination = if (isFirstStart) ScreensDestination.Welcome.screenRoute else ScreensDestination.Root.screenRoute, - startDestination = ScreensDestination.Settings.screenRoute, + startDestination = if (isFirstStart) ScreensDestination.Welcome.screenRoute else ScreensDestination.Root.screenRoute, modifier = modifier ) { composable( diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt index 055062a8..c9a156b1 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt @@ -548,6 +548,8 @@ fun BooleanFlagsScreen( viewModel.initOverriddenBoolFlags(packageName.toString()) haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) }, + saveChecked = true, // TODO: Implement saveChecked + saveOnCheckedChange = {}, // TODO: Implement saveOnCheckedChange lastItem = index == listBool.size - 1, ) } @@ -648,10 +650,8 @@ fun OtherTypesFlagsScreen( flagName = listInt.keys.toList()[index], flagValue = listInt.values.toList()[index], lastItem = index == listInt.size - 1, - savedButtonChecked = false, - savedButtonOnChecked = {}, - haptic = haptic, - context = context, + saveChecked = false, // TODO: Implement saveChecked + saveOnCheckedChange = {}, // TODO: Implement saveOnCheckedChange onClick = { onFlagClick( item.first, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagsItemTypes.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagsItemTypes.kt index f21c52d4..e9574141 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagsItemTypes.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagsItemTypes.kt @@ -38,6 +38,8 @@ fun BoolValItem( checked: Boolean, lastItem: Boolean = false, onCheckedChange: (Boolean) -> Unit, + saveChecked: Boolean, + saveOnCheckedChange: (Boolean) -> Unit, modifier: Modifier = Modifier ) { @@ -59,16 +61,16 @@ fun BoolValItem( .background(if (!select) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.surfaceContainerHighest) .padding(vertical = 8.dp), verticalAlignment = Alignment.CenterVertically ) { - IconToggleButton(checked = false, onCheckedChange = { }) { // todo - if (false) { //todo + IconToggleButton(checked = saveChecked, onCheckedChange = saveOnCheckedChange) { + if (saveChecked) { Icon( painterResource(id = R.drawable.ic_save_active), - contentDescription = "Localized description" + contentDescription = null ) } else { Icon( painterResource(id = R.drawable.ic_save_inactive), - contentDescription = "Localized description" + contentDescription = null ) } } @@ -94,10 +96,8 @@ fun IntFloatStringValItem( flagName: String, flagValue: String, lastItem: Boolean = false, - savedButtonChecked: Boolean, - savedButtonOnChecked: (Boolean) -> Unit, - haptic: HapticFeedback, - context: Context, + saveChecked: Boolean, + saveOnCheckedChange: (Boolean) -> Unit, onClick: () -> Unit, onLongClick: () -> Unit, modifier: Modifier = Modifier @@ -125,10 +125,10 @@ fun IntFloatStringValItem( ) { IconToggleButton( - checked = savedButtonChecked, - onCheckedChange = savedButtonOnChecked + checked = saveChecked, + onCheckedChange = saveOnCheckedChange ) { // todo - if (savedButtonChecked) { //todo + if (saveChecked) { //todo Icon( painterResource(id = R.drawable.ic_save_active), contentDescription = "Localized description" diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt index c9f72845..fd5c0ccf 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt @@ -1,5 +1,6 @@ package ua.polodarb.gmsflags.ui.screens.savedScreen +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -7,7 +8,9 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Divider +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconToggleButton import androidx.compose.material3.MaterialTheme @@ -22,50 +25,49 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import ua.polodarb.gmsflags.R +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags @Composable -fun SavedFlagsScreen() { +fun SavedFlagsScreen( + savedFlagsList: List, + viewModel: SavedScreenViewModel, + onFlagClick: (packageName: String, flagName: String) -> Unit +) { + Column( modifier = Modifier.fillMaxSize() ) { - LazyColumn { - items(20) { - LazyFlagsItem(flagName = "flagName", packageName = "packageName", index = it) + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { + itemsIndexed(savedFlagsList.toList()) { index, item -> + SavedFlagsLazyItem( + packageName = item.pkgName, + flagName = item.flagName, + checked = savedFlagsList.contains(SavedFlags(item.pkgName, item.flagName, item.type)), // todo ?? + onCheckedChange = { + if (!it) viewModel.deleteSavedFlag(item.flagName, item.pkgName) + }, + lastItem = savedFlagsList.size - 1 == index, + modifier = Modifier.clickable { + onFlagClick(item.pkgName, item.flagName) + } + ) } } } } @Composable -fun LazyFlagsItem( - flagName: String, - packageName: String, +fun SavedFlagsLazyItem( modifier: Modifier = Modifier, - index: Int -) { - var checkedState by rememberSaveable { - mutableStateOf(false) - } - - LazyFlagsItem( - flagName = flagName, - packageName = packageName, - modifier = modifier, - checked = checkedState, - onCheckedChange = { checked -> - checkedState = checked - } - ) -} - -@Composable -fun LazyFlagsItem( - flagName: String, packageName: String, + flagName: String, checked: Boolean, onCheckedChange: (Boolean) -> Unit, - modifier: Modifier = Modifier + lastItem: Boolean, ) { Column { Row( @@ -77,26 +79,26 @@ fun LazyFlagsItem( if (checked) { Icon( painterResource(id = R.drawable.ic_save_active), - contentDescription = "Localized description" + contentDescription = null ) } else { Icon( painterResource(id = R.drawable.ic_save_inactive), - contentDescription = "Localized description" + contentDescription = null ) } } - Column(Modifier.weight(0.9f), verticalArrangement = Arrangement.Center) { - Text(text = packageName, style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.outline) - Text(text = flagName, style = MaterialTheme.typography.bodyLarge) + Column(Modifier.weight(0.9f)) { + Text(text = packageName, fontSize = 13.sp, color = MaterialTheme.colorScheme.outline) + Text(text = flagName, fontSize = 15.sp) } - Switch( - checked = false, onCheckedChange = { - - }, modifier = Modifier - .padding(horizontal = 16.dp) + Icon( + modifier = Modifier + .padding(16.dp), + painter = painterResource(id = R.drawable.ic_next), + contentDescription = null ) } } - Divider(Modifier.padding(horizontal = 16.dp)) -} \ No newline at end of file + if (!lastItem) HorizontalDivider(Modifier.padding(horizontal = 16.dp)) +} diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt index 1c0a87a8..c8e2d298 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedPackagesScreen.kt @@ -28,7 +28,7 @@ import ua.polodarb.gmsflags.R fun SavedPackagesScreen( savedPackagesList: List, viewModel: SavedScreenViewModel, - onFlagClick: (packageName: String) -> Unit + onPackageClick: (packageName: String) -> Unit ) { Column( @@ -46,7 +46,7 @@ fun SavedPackagesScreen( }, lastItem = savedPackagesList.size - 1 == index, modifier = Modifier.clickable { - onFlagClick(item) + onPackageClick(item) } ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt index c9cf8a91..76e6694d 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt @@ -68,11 +68,13 @@ import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionScreenViewMod fun SavedScreen( onSettingsClick: () -> Unit, onPackagesClick: () -> Unit, - onFlagClick: (packageName: String) -> Unit, + onSavedPackageClick: (packageName: String) -> Unit, + onSavedFlagClick: (packageName: String, flagName: String) -> Unit, ) { val viewModel = koinViewModel() val savedPackages = viewModel.stateSavedPackages.collectAsState() + val savedFlags = viewModel.stateSavedFlags.collectAsState() val topBarState = rememberTopAppBarState() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(topBarState) @@ -187,10 +189,13 @@ fun SavedScreen( 0 -> SavedPackagesScreen( savedPackagesList = savedPackages.value, viewModel = viewModel, - onFlagClick = onFlagClick + onPackageClick = onSavedPackageClick + ) + 1 -> SavedFlagsScreen( + savedFlagsList = savedFlags.value, + viewModel = viewModel, + onFlagClick = onSavedFlagClick ) -// 1 -> SavedFlagsScreen() - 1 -> NotImplementedScreen() } } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt index 1841bf69..4d90e2f0 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.data.repo.RoomDBRepository import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionsScreenUiStates @@ -19,11 +20,16 @@ class SavedScreenViewModel( MutableStateFlow>(emptyList()) val stateSavedPackages: StateFlow> = _stateSavedPackages.asStateFlow() + private val _stateSavedFlags = + MutableStateFlow>(emptyList()) + val stateSavedFlags: StateFlow> = _stateSavedFlags.asStateFlow() + init { getAllSavedPackages() } - fun getAllSavedPackages() { + // Packages + private fun getAllSavedPackages() { viewModelScope.launch { withContext(Dispatchers.IO) { roomRepository.getSavedPackages().collect { @@ -41,4 +47,23 @@ class SavedScreenViewModel( } } + // Flags + private fun getAllSavedFlags() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.getSavedFlags().collect { + _stateSavedFlags.value = it + } + } + } + } + + fun deleteSavedFlag(flagName: String, pkgName: String) { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.deleteSavedFlag(flagName, pkgName) + } + } + } + } \ No newline at end of file From 61fda512141b50208ebc2f238a494146f1e793bf Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 26 Sep 2023 01:01:40 +0300 Subject: [PATCH 09/24] Fully implemented the logic of saving flags --- .../databases/local/enities/SavedFlags.kt | 5 +- .../polodarb/gmsflags/di/ViewModelsModule.kt | 3 +- .../gmsflags/ui/navigation/AppNavigation.kt | 6 +- .../gmsflags/ui/navigation/NavigationBarUI.kt | 3 +- .../flagChangeScreen/FlagChangeScreen.kt | 69 +++++++++++++++---- .../FlagChangeScreenViewModel.kt | 39 ++++++++++- .../packagesScreen/PackagesScreenViewModel.kt | 1 + .../screens/savedScreen/SavedFlagsScreen.kt | 61 +++++++++++----- .../ui/screens/savedScreen/SavedScreen.kt | 12 ++-- .../savedScreen/SavedScreenViewModel.kt | 1 + build.gradle.kts | 4 +- 11 files changed, 159 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt index 0645d85f..1f877927 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/local/enities/SavedFlags.kt @@ -6,7 +6,8 @@ import androidx.room.PrimaryKey @Entity(tableName = "saved_flags") data class SavedFlags( - @PrimaryKey @ColumnInfo(name = "pkg_name") val pkgName: String, + @ColumnInfo(name = "pkg_name") val pkgName: String, @ColumnInfo(name = "flag_name") val flagName: String, - @ColumnInfo(name = "flag_type") val type: String + @ColumnInfo(name = "flag_type") val type: String, + @PrimaryKey(autoGenerate = true) val id: Int = 0 ) \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt index b832a34f..17eac8b8 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt @@ -20,7 +20,8 @@ val viewModelsModule = module { viewModel { FlagChangeScreenViewModel( pkgName = get(), - repository = get() + repository = get(), + roomRepository = get() ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index 69c74fb0..9d19ba28 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -118,8 +118,10 @@ internal fun BottomBarNavigation( // Navigation realization for BottomBar ScreensDestination.FlagChange.createRoute(Uri.encode(it)) ) }, - onSavedFlagClick = { packageName, flagName -> - // TODO: Implement navigation to flags list + onSavedFlagClick = { packageName, flagName, type -> + parentNavController.navigate( + ScreensDestination.FlagChange.createRoute(Uri.encode(packageName)) // TODO: Implement search flag in list after navigation + ) } ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/NavigationBarUI.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/NavigationBarUI.kt index 6713be44..ba640231 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/NavigationBarUI.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/NavigationBarUI.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow import androidx.navigation.NavHostController @Composable @@ -30,7 +31,7 @@ fun BottomBarUI( contentDescription = stringResource(id = item.title) ) }, - label = { Text(text = stringResource(id = item.title)) }, + label = { Text(text = stringResource(id = item.title), maxLines = 1, overflow = TextOverflow.Ellipsis) }, selected = currentSelectedItem == item, onClick = { navController.navigate(item.screenRoute) { diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt index c9a156b1..860dc26b 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt @@ -63,6 +63,7 @@ import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.core.Extensions.toInt +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.ui.components.chips.GFlagFilterChipRow import ua.polodarb.gmsflags.ui.components.dropDown.FlagChangeDropDown import ua.polodarb.gmsflags.ui.components.inserts.ErrorLoadScreen @@ -92,6 +93,8 @@ fun FlagChangeScreen( val uiStateFloat = viewModel.stateFloat.collectAsState() val uiStateString = viewModel.stateString.collectAsState() + val savedFlags = viewModel.stateSavedFlags.collectAsState() + val topBarState = rememberTopAppBarState() val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(topBarState) val clipboardManager = LocalClipboardManager.current @@ -352,12 +355,28 @@ fun FlagChangeScreen( contentPadding = PaddingValues(top = paddingValues.calculateTopPadding()) ) { page -> when (page) { - 0 -> BooleanFlagsScreen( - uiState = uiStateBoolean.value, - viewModel = viewModel, - packageName = packageName.toString(), - haptic = haptic - ) + 0 -> { + when (uiStateBoolean.value) { + is FlagChangeUiStates.Success -> { + + val listBool = (uiStateBoolean.value as FlagChangeUiStates.Success).data.toSortedMap(compareByDescending { + it.toIntOrNull() ?: 0 + }.thenBy { it }) + + BooleanFlagsScreen( + listBool = listBool, + uiState = uiStateBoolean.value, + viewModel = viewModel, + packageName = packageName.toString(), + haptic = haptic, + savedFlagsList = savedFlags.value + ) + } + is FlagChangeUiStates.Loading -> {} + is FlagChangeUiStates.Error -> {} + } + + } 1 -> OtherTypesFlagsScreen( uiState = uiStateInteger.value, @@ -513,7 +532,9 @@ fun FlagChangeScreen( @Composable fun BooleanFlagsScreen( + listBool: Map, uiState: FlagChangeUiStates, + savedFlagsList: List, viewModel: FlagChangeScreenViewModel, packageName: String?, haptic: HapticFeedback @@ -521,17 +542,23 @@ fun BooleanFlagsScreen( when (uiState) { is FlagChangeUiStates.Success -> { - val listBool = uiState.data.toSortedMap(compareByDescending { - it.toIntOrNull() ?: 0 - }.thenBy { it }) - if (listBool.isEmpty()) NoFlagsOrPackages() - Box(modifier = Modifier.fillMaxSize().imePadding()) { + Box(modifier = Modifier + .fillMaxSize() + .imePadding()) { if (listBool.isNotEmpty()) { LazyColumn { itemsIndexed(listBool.keys.toList()) { index, flagName -> + val checked = listBool.values.toList()[index] == "1" + val targetFlag = SavedFlags(packageName.toString(), flagName, SelectFlagsType.BOOLEAN.name) + val isEqual = savedFlagsList.any { (packageName, flag, selectFlagsType, _) -> + packageName == targetFlag.pkgName && + flag == targetFlag.flagName && + selectFlagsType == targetFlag.type + } + BoolValItem( flagName = flagName, checked = checked, @@ -548,8 +575,14 @@ fun BooleanFlagsScreen( viewModel.initOverriddenBoolFlags(packageName.toString()) haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) }, - saveChecked = true, // TODO: Implement saveChecked - saveOnCheckedChange = {}, // TODO: Implement saveOnCheckedChange + saveChecked = isEqual, + saveOnCheckedChange = { + if (it) { + viewModel.saveFlag(flagName, packageName.toString(), SelectFlagsType.BOOLEAN.name) + } else { + viewModel.deleteSavedFlag(flagName, packageName.toString()) + } + }, lastItem = index == listBool.size - 1, ) } @@ -594,12 +627,16 @@ fun OtherTypesFlagsScreen( is FlagChangeUiStates.Success -> { val textFlagType = when (flagsType) { + SelectFlagsType.BOOLEAN -> "Boolean" SelectFlagsType.INTEGER -> "Integer" SelectFlagsType.FLOAT -> "Float" SelectFlagsType.STRING -> "String" } fun setViewModelMethods() = when (flagsType) { + + SelectFlagsType.BOOLEAN -> {} + SelectFlagsType.INTEGER -> { viewModel.overrideFlag( packageName = packageName.toString(), @@ -642,7 +679,9 @@ fun OtherTypesFlagsScreen( if (listInt.isEmpty()) NoFlagsOrPackages() - Box(modifier = Modifier.fillMaxSize().imePadding()) { + Box(modifier = Modifier + .fillMaxSize() + .imePadding()) { if (listInt.isNotEmpty()) { LazyColumn { itemsIndexed(listInt.toList()) { index, item -> @@ -713,5 +752,5 @@ fun OtherTypesFlagsScreen( } enum class SelectFlagsType { - INTEGER, FLOAT, STRING + BOOLEAN, INTEGER, FLOAT, STRING } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt index f1a9e00c..e209c34e 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt @@ -12,11 +12,14 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.data.repo.GmsDBRepository +import ua.polodarb.gmsflags.data.repo.RoomDBRepository class FlagChangeScreenViewModel( private val pkgName: String, - private val repository: GmsDBRepository + private val repository: GmsDBRepository, + private val roomRepository: RoomDBRepository ) : ViewModel() { private val _stateBoolean = @@ -35,6 +38,11 @@ class FlagChangeScreenViewModel( MutableStateFlow(FlagChangeUiStates.Loading) val stateString: StateFlow = _stateString.asStateFlow() + private val _stateSavedFlags = + MutableStateFlow>(emptyList()) + val stateSavedFlags: StateFlow> = _stateSavedFlags.asStateFlow() + + // Filter var filterMethod = mutableStateOf(FilterMethod.ALL) @@ -111,6 +119,7 @@ class FlagChangeScreenViewModel( init { usersList.addAll(repository.getUsers()) + getAllSavedFlags() initBoolValues() initIntValues() initFloatValues() @@ -363,6 +372,34 @@ class FlagChangeScreenViewModel( repository.deleteOverriddenFlagByPackage(packageName) } + // Saved flags + + private fun getAllSavedFlags() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.getSavedFlags().collect { + _stateSavedFlags.value = it + } + } + } + } + + fun saveFlag(flagName: String, pkgName: String, flagType: String) { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.saveFlag(flagName, pkgName, flagType) + } + } + } + + fun deleteSavedFlag(flagName: String, pkgName: String) { + viewModelScope.launch { + withContext(Dispatchers.IO) { + roomRepository.deleteSavedFlag(flagName, pkgName) + } + } + } + } enum class FilterMethod : MutableState { diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt index cd5d206c..61cbab5d 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/packagesScreen/PackagesScreenViewModel.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags import ua.polodarb.gmsflags.data.repo.GmsDBRepository import ua.polodarb.gmsflags.data.repo.RoomDBRepository import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionsScreenUiStates diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt index fd5c0ccf..5dc6ff13 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt @@ -1,7 +1,10 @@ package ua.polodarb.gmsflags.ui.screens.savedScreen +import android.util.Log +import android.widget.Toast +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize @@ -9,33 +12,37 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.Divider import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconToggleButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.data.databases.local.enities.SavedFlags +import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.SelectFlagsType +@OptIn(ExperimentalFoundationApi::class) @Composable fun SavedFlagsScreen( savedFlagsList: List, viewModel: SavedScreenViewModel, - onFlagClick: (packageName: String, flagName: String) -> Unit + onFlagClick: (packageName: String, flagName: String, type: String) -> Unit ) { + val clipboardManager = LocalClipboardManager.current + val haptic = LocalHapticFeedback.current + Column( modifier = Modifier.fillMaxSize() ) { @@ -43,17 +50,31 @@ fun SavedFlagsScreen( modifier = Modifier.fillMaxSize() ) { itemsIndexed(savedFlagsList.toList()) { index, item -> + + val targetFlag = SavedFlags(item.pkgName, item.flagName, SelectFlagsType.BOOLEAN.name) + val isEqual = savedFlagsList.any { (packageName, flag, selectFlagsType, _) -> + packageName == targetFlag.pkgName && + flag == targetFlag.flagName && + selectFlagsType == targetFlag.type + } + SavedFlagsLazyItem( packageName = item.pkgName, flagName = item.flagName, - checked = savedFlagsList.contains(SavedFlags(item.pkgName, item.flagName, item.type)), // todo ?? + checked = isEqual, onCheckedChange = { if (!it) viewModel.deleteSavedFlag(item.flagName, item.pkgName) }, lastItem = savedFlagsList.size - 1 == index, - modifier = Modifier.clickable { - onFlagClick(item.pkgName, item.flagName) - } + modifier = Modifier.combinedClickable( + onClick = { + onFlagClick(item.pkgName, item.flagName, item.type) + }, + onLongClick = { + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + clipboardManager.setText(AnnotatedString(item.flagName)) + } + ) ) } } @@ -69,11 +90,18 @@ fun SavedFlagsLazyItem( onCheckedChange: (Boolean) -> Unit, lastItem: Boolean, ) { - Column { + Column( + modifier = modifier.fillMaxWidth() + ) { + Text( + text = packageName, + fontSize = 13.sp, + color = MaterialTheme.colorScheme.outline, + modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp) + ) Row( - modifier = modifier - .fillMaxWidth() - .padding(vertical = 8.dp), verticalAlignment = Alignment.CenterVertically + modifier = Modifier + .padding(bottom = 4.dp), verticalAlignment = Alignment.CenterVertically ) { IconToggleButton(checked = checked, onCheckedChange = onCheckedChange) { if (checked) { @@ -89,7 +117,6 @@ fun SavedFlagsLazyItem( } } Column(Modifier.weight(0.9f)) { - Text(text = packageName, fontSize = 13.sp, color = MaterialTheme.colorScheme.outline) Text(text = flagName, fontSize = 15.sp) } Icon( diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt index 76e6694d..d8cd2aaf 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreen.kt @@ -1,5 +1,6 @@ package ua.polodarb.gmsflags.ui.screens.savedScreen +import android.util.Log import android.widget.Toast import androidx.compose.animation.core.FastOutLinearInEasing import androidx.compose.animation.core.animateDp @@ -61,6 +62,7 @@ import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.ui.components.inserts.NotImplementedScreen +import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.SelectFlagsType import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionScreenViewModel @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @@ -69,7 +71,7 @@ fun SavedScreen( onSettingsClick: () -> Unit, onPackagesClick: () -> Unit, onSavedPackageClick: (packageName: String) -> Unit, - onSavedFlagClick: (packageName: String, flagName: String) -> Unit, + onSavedFlagClick: (packageName: String, flagName: String, type: String) -> Unit, ) { val viewModel = koinViewModel() @@ -91,6 +93,8 @@ fun SavedScreen( 2 }) + Log.e("flag", savedFlags.value.toString()) + val coroutineScope = rememberCoroutineScope() Scaffold( @@ -182,17 +186,17 @@ fun SavedScreen( } HorizontalPager( state = pagerState, - userScrollEnabled = false, + userScrollEnabled = true, contentPadding = PaddingValues(top = paddingValues.calculateTopPadding()) ) { page -> when (page) { 0 -> SavedPackagesScreen( - savedPackagesList = savedPackages.value, + savedPackagesList = savedPackages.value.reversed(), viewModel = viewModel, onPackageClick = onSavedPackageClick ) 1 -> SavedFlagsScreen( - savedFlagsList = savedFlags.value, + savedFlagsList = savedFlags.value.reversed(), viewModel = viewModel, onFlagClick = onSavedFlagClick ) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt index 4d90e2f0..e57b08a9 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedScreenViewModel.kt @@ -26,6 +26,7 @@ class SavedScreenViewModel( init { getAllSavedPackages() + getAllSavedFlags() } // Packages diff --git a/build.gradle.kts b/build.gradle.kts index 5c2d1962..90c83d75 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.1.0" apply false - id("com.android.library") version "8.1.0" apply false + id("com.android.application") version "8.1.1" apply false + id("com.android.library") version "8.1.1" apply false id("org.jetbrains.kotlin.android") version "1.9.0" apply false id("com.google.devtools.ksp") version "1.9.0-1.0.12" apply false id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0" From 3ee747e30e49afcdba0ef6ed4bc48c093a9a75ce Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 26 Sep 2023 01:26:38 +0300 Subject: [PATCH 10/24] Chips for other flag types has been disabled --- .../ui/components/chips/GFlagFilterChip.kt | 16 ++-- .../ui/components/chips/GFlagFilterChipRow.kt | 2 + .../flagChangeScreen/FlagChangeScreen.kt | 84 +++++++++++-------- .../suggestionsScreen/SuggestionsScreen.kt | 6 +- 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChip.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChip.kt index 3ef20803..3326300f 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChip.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChip.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.text.style.TextOverflow @Composable fun GFlagFilterChip( selected: Boolean, + pagerCurrentState: Int, chipOnClick: () -> Unit, chipTitle: String, modifier: Modifier @@ -29,12 +30,16 @@ fun GFlagFilterChip( leadingIconColor = Color.Transparent, trailingIconColor = Color.Transparent, disabledContainerColor = Color.Transparent, - disabledLabelColor = Color.Transparent, + disabledLabelColor = MaterialTheme.colorScheme.onSecondaryContainer.copy( + alpha = 0.3f + ), disabledLeadingIconColor = Color.Transparent, disabledTrailingIconColor = Color.Transparent, - selectedContainerColor = MaterialTheme.colorScheme.surfaceVariant, - disabledSelectedContainerColor = Color.Transparent, - selectedLabelColor = MaterialTheme.colorScheme.onSurfaceVariant, + selectedContainerColor = MaterialTheme.colorScheme.secondary, + disabledSelectedContainerColor = MaterialTheme.colorScheme.secondary.copy( + alpha = 0.2f + ), + selectedLabelColor = MaterialTheme.colorScheme.onSecondary, selectedLeadingIconColor = Color.Transparent, selectedTrailingIconColor = Color.Transparent ), @@ -48,6 +53,7 @@ fun GFlagFilterChip( ) }, leadingIcon = null, - modifier = modifier + modifier = modifier, + enabled = pagerCurrentState == 0 ) } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChipRow.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChipRow.kt index 80ddc550..6031e808 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChipRow.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/components/chips/GFlagFilterChipRow.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.unit.dp fun GFlagFilterChipRow( list: List, selectedChips: Int, + pagerCurrentState: Int, chipOnClick: (index: Int) -> Unit ) { @@ -27,6 +28,7 @@ fun GFlagFilterChipRow( list.forEachIndexed { index, title -> GFlagFilterChip( selected = selectedChips == index, + pagerCurrentState = pagerCurrentState, chipOnClick = { chipOnClick(index) }, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt index 860dc26b..171849f3 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt @@ -213,24 +213,22 @@ fun FlagChangeScreen( ) }, actions = { - AnimatedVisibility(visible = tabFilterState) { - IconButton( - onClick = { - if (searchIconState) searchIconState = false - viewModel.initOverriddenBoolFlags(packageName.toString()) //todo - filterIconState = !filterIconState - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - }, - modifier = if (filterIconState) Modifier - .clip(CircleShape) - .background(MaterialTheme.colorScheme.surfaceContainerHighest) - else Modifier.background(Color.Transparent) - ) { - Icon( - painter = painterResource(id = R.drawable.ic_filter), - contentDescription = "Filter" - ) - } + IconButton( + onClick = { + if (searchIconState) searchIconState = false + viewModel.initOverriddenBoolFlags(packageName.toString()) //todo + filterIconState = !filterIconState + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + }, + modifier = if (filterIconState) Modifier + .clip(CircleShape) + .background(MaterialTheme.colorScheme.surfaceContainerHighest) + else Modifier.background(Color.Transparent) + ) { + Icon( + painter = painterResource(id = R.drawable.ic_filter), + contentDescription = "Filter" + ) } IconButton( onClick = { @@ -298,7 +296,6 @@ fun FlagChangeScreen( coroutineScope.launch { pagerState.scrollToPage(index) } - if (index != 0) filterIconState = false tabFilterState = index == 0 tabState = index } @@ -307,6 +304,7 @@ fun FlagChangeScreen( GFlagFilterChipRow( list = chipsList, selectedChips = selectedChips, + pagerCurrentState = pagerState.currentPage, chipOnClick = { when (it) { 0 -> viewModel.filterMethod.value = ALL @@ -359,9 +357,11 @@ fun FlagChangeScreen( when (uiStateBoolean.value) { is FlagChangeUiStates.Success -> { - val listBool = (uiStateBoolean.value as FlagChangeUiStates.Success).data.toSortedMap(compareByDescending { - it.toIntOrNull() ?: 0 - }.thenBy { it }) + val listBool = + (uiStateBoolean.value as FlagChangeUiStates.Success).data.toSortedMap( + compareByDescending { + it.toIntOrNull() ?: 0 + }.thenBy { it }) BooleanFlagsScreen( listBool = listBool, @@ -372,6 +372,7 @@ fun FlagChangeScreen( savedFlagsList = savedFlags.value ) } + is FlagChangeUiStates.Loading -> {} is FlagChangeUiStates.Error -> {} } @@ -544,20 +545,27 @@ fun BooleanFlagsScreen( if (listBool.isEmpty()) NoFlagsOrPackages() - Box(modifier = Modifier - .fillMaxSize() - .imePadding()) { + Box( + modifier = Modifier + .fillMaxSize() + .imePadding() + ) { if (listBool.isNotEmpty()) { LazyColumn { itemsIndexed(listBool.keys.toList()) { index, flagName -> val checked = listBool.values.toList()[index] == "1" - val targetFlag = SavedFlags(packageName.toString(), flagName, SelectFlagsType.BOOLEAN.name) - val isEqual = savedFlagsList.any { (packageName, flag, selectFlagsType, _) -> - packageName == targetFlag.pkgName && - flag == targetFlag.flagName && - selectFlagsType == targetFlag.type - } + val targetFlag = SavedFlags( + packageName.toString(), + flagName, + SelectFlagsType.BOOLEAN.name + ) + val isEqual = + savedFlagsList.any { (packageName, flag, selectFlagsType, _) -> + packageName == targetFlag.pkgName && + flag == targetFlag.flagName && + selectFlagsType == targetFlag.type + } BoolValItem( flagName = flagName, @@ -578,7 +586,11 @@ fun BooleanFlagsScreen( saveChecked = isEqual, saveOnCheckedChange = { if (it) { - viewModel.saveFlag(flagName, packageName.toString(), SelectFlagsType.BOOLEAN.name) + viewModel.saveFlag( + flagName, + packageName.toString(), + SelectFlagsType.BOOLEAN.name + ) } else { viewModel.deleteSavedFlag(flagName, packageName.toString()) } @@ -679,9 +691,11 @@ fun OtherTypesFlagsScreen( if (listInt.isEmpty()) NoFlagsOrPackages() - Box(modifier = Modifier - .fillMaxSize() - .imePadding()) { + Box( + modifier = Modifier + .fillMaxSize() + .imePadding() + ) { if (listInt.isNotEmpty()) { LazyColumn { itemsIndexed(listInt.toList()) { index, item -> diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index 97f98a53..388f67d2 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -1,6 +1,5 @@ package ua.polodarb.gmsflags.ui.screens.suggestionsScreen -import android.util.Log import android.widget.Toast import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -80,7 +79,10 @@ fun SuggestionsScreen( ) { ExtendedFloatingActionButton( containerColor = MaterialTheme.colorScheme.secondaryContainer, - onClick = { /* do something */ }, + onClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + Toast.makeText(context, "Not implemented", Toast.LENGTH_SHORT).show() + }, expanded = expandedFab, icon = { Icon(painterResource(id = R.drawable.ic_question), "") }, text = { Text(text = "How can I suggest or report a flag?") }, From fa95acfc8eaa3f84e6b751a11459bee6f006ad0b Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 26 Sep 2023 17:15:25 +0300 Subject: [PATCH 11/24] Fix saving flags for int\float\string types --- .../flagChangeScreen/FlagChangeScreen.kt | 41 ++++++++++++++++--- .../screens/savedScreen/SavedFlagsScreen.kt | 2 +- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt index 171849f3..e1a1ea23 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt @@ -1,6 +1,7 @@ package ua.polodarb.gmsflags.ui.screens.flagChangeScreen import android.content.Context +import android.util.Log import android.widget.Toast import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.ExperimentalFoundationApi @@ -406,7 +407,8 @@ fun FlagChangeScreen( editTextValue.value = flagValue }, haptic = haptic, - context = context + context = context, + savedFlagsList = savedFlags.value ) 2 -> OtherTypesFlagsScreen( @@ -436,7 +438,8 @@ fun FlagChangeScreen( editTextValue.value = flagValue }, haptic = haptic, - context = context + context = context, + savedFlagsList = savedFlags.value ) 3 -> OtherTypesFlagsScreen( @@ -466,7 +469,8 @@ fun FlagChangeScreen( editTextValue.value = flagValue }, haptic = haptic, - context = context + context = context, + savedFlagsList = savedFlags.value ) } } @@ -628,6 +632,7 @@ fun OtherTypesFlagsScreen( flagsType: SelectFlagsType, editTextValue: String, showDialog: Boolean, + savedFlagsList: List, onFlagClick: (flagName: String, flagValue: String, editTextValue: String, showDialog: Boolean) -> Unit, dialogOnQueryChange: (String) -> Unit, dialogOnConfirm: () -> Unit, @@ -699,12 +704,38 @@ fun OtherTypesFlagsScreen( if (listInt.isNotEmpty()) { LazyColumn { itemsIndexed(listInt.toList()) { index, item -> + + val targetFlag = SavedFlags( + packageName.toString(), + item.first, + flagsType.name + ) + val isEqual = + savedFlagsList.any { (packageName, flag, selectFlagsType, _) -> + packageName == targetFlag.pkgName && + flag == targetFlag.flagName && + selectFlagsType == targetFlag.type + } + + Log.e("flag", targetFlag.toString()) + Log.e("flag", isEqual.toString()) + IntFloatStringValItem( flagName = listInt.keys.toList()[index], flagValue = listInt.values.toList()[index], lastItem = index == listInt.size - 1, - saveChecked = false, // TODO: Implement saveChecked - saveOnCheckedChange = {}, // TODO: Implement saveOnCheckedChange + saveChecked = isEqual, + saveOnCheckedChange = { + if (it) { + viewModel.saveFlag( + item.first, + packageName.toString(), + flagsType.name + ) + } else { + viewModel.deleteSavedFlag(item.first, packageName.toString()) + } + }, onClick = { onFlagClick( item.first, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt index 5dc6ff13..bd77dc91 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/savedScreen/SavedFlagsScreen.kt @@ -51,7 +51,7 @@ fun SavedFlagsScreen( ) { itemsIndexed(savedFlagsList.toList()) { index, item -> - val targetFlag = SavedFlags(item.pkgName, item.flagName, SelectFlagsType.BOOLEAN.name) + val targetFlag = SavedFlags(item.pkgName, item.flagName, item.type) val isEqual = savedFlagsList.any { (packageName, flag, selectFlagsType, _) -> packageName == targetFlag.pkgName && flag == targetFlag.flagName && From a6900342c4b5b3289d9897d040c0e95634bb5b52 Mon Sep 17 00:00:00 2001 From: polodarb Date: Tue, 26 Sep 2023 18:16:57 +0300 Subject: [PATCH 12/24] Implemented warning banner on SuggestionsScreen --- .../gmsflags/ui/navigation/AppNavigation.kt | 2 + .../ui/navigation/RootAppNavigation.kt | 2 +- .../gmsflags/ui/screens/RootScreen.kt | 2 + .../suggestionsScreen/SuggestionsScreen.kt | 84 ++++++++++++++++++- 4 files changed, 87 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index 9d19ba28..689ebd01 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -71,6 +71,7 @@ internal sealed class ScreensDestination(var screenRoute: String) { @Composable internal fun BottomBarNavigation( // Navigation realization for BottomBar + isFirstStart: Boolean, modifier: Modifier = Modifier, parentNavController: NavController, navController: NavHostController @@ -82,6 +83,7 @@ internal fun BottomBarNavigation( // Navigation realization for BottomBar ) { composable(route = NavBarItem.Suggestions.screenRoute) { SuggestionsScreen( + isFirstStart = isFirstStart, onSettingsClick = { parentNavController.navigate(ScreensDestination.Settings.screenRoute) }, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt index 38665264..3e1b71f4 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt @@ -107,7 +107,7 @@ internal fun RootAppNavigation( enterTransition = { enterAnim(toLeft = false) }, exitTransition = { exitAnim(toLeft = true) } ) { - RootScreen(parentNavController = navController) + RootScreen(isFirstStart = isFirstStart, parentNavController = navController) } composable( route = ScreensDestination.Welcome.screenRoute, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/RootScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/RootScreen.kt index 38eeedfc..cb958ecf 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/RootScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/RootScreen.kt @@ -13,6 +13,7 @@ import ua.polodarb.gmsflags.ui.navigation.BottomBarUI @Composable fun RootScreen( + isFirstStart: Boolean, parentNavController: NavController, childNavController: NavHostController = rememberNavController() ) { @@ -20,6 +21,7 @@ fun RootScreen( bottomBar = { BottomBarUI(navController = childNavController) } ) { paddingValues -> BottomBarNavigation( + isFirstStart = isFirstStart, parentNavController = parentNavController, navController = childNavController, modifier = Modifier diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index 388f67d2..74919c61 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -1,19 +1,31 @@ package ua.polodarb.gmsflags.ui.screens.suggestionsScreen import android.widget.Toast +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.outlined.Settings +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.FabPosition @@ -33,13 +45,18 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import org.koin.androidx.compose.koinViewModel @@ -50,6 +67,7 @@ import ua.polodarb.gmsflags.ui.components.inserts.LoadingProgressBar @OptIn(ExperimentalMaterial3Api::class) @Composable fun SuggestionsScreen( + isFirstStart: Boolean, onSettingsClick: () -> Unit, onPackagesClick: () -> Unit ) { @@ -133,7 +151,9 @@ fun SuggestionsScreen( } ) { it -> Column( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() + .padding(top = it.calculateTopPadding()) ) { when (overriddenFlags.value) { is SuggestionsScreenUiStates.Success -> { @@ -141,9 +161,11 @@ fun SuggestionsScreen( val data = (overriddenFlags.value as SuggestionsScreenUiStates.Success).data LazyColumn( - contentPadding = it, state = listState ) { + item { + WarningBanner(isFirstStart) + } itemsIndexed(data.toList()) { index, item -> SuggestedFlagItem( flagName = item.flagName, @@ -203,4 +225,62 @@ fun SuggestedFlagItem( } }, ) +} + +@Composable +fun WarningBanner( + isFirstStart: Boolean +) { + var visibility by rememberSaveable { + mutableStateOf(isFirstStart) + } + + AnimatedVisibility(visible = visibility, enter = fadeIn(), exit = fadeOut() + shrinkVertically()) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + .clip(RoundedCornerShape(24.dp)) + .background(MaterialTheme.colorScheme.errorContainer) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp) + ) { + Image( + painter = painterResource(id = R.drawable.ic_force_stop), + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.error), + modifier = Modifier + .padding(8.dp) + .size(28.dp) + ) + Text( + text = "To apply the flag, you need to click \"Force stop\" several times in the settings on the *target* App info settings page.", + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 4.dp), + fontWeight = FontWeight.Medium, + color = MaterialTheme.colorScheme.onErrorContainer + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + Button( + onClick = { visibility = false }, + modifier = Modifier.padding(8.dp), + colors = ButtonColors( + containerColor = MaterialTheme.colorScheme.error, + contentColor = MaterialTheme.colorScheme.onError, + disabledContainerColor = MaterialTheme.colorScheme.outline, + disabledContentColor = MaterialTheme.colorScheme.onSurfaceVariant + ) + ) { + Text(text = "Close") + } + } + } + } + } } \ No newline at end of file From 55f75b9ed4556e6450551523f29f8ce78cb6aa51 Mon Sep 17 00:00:00 2001 From: polodarb Date: Wed, 27 Sep 2023 21:17:21 +0300 Subject: [PATCH 13/24] Implemented Setting-About screen --- .../gmsflags/ui/navigation/AppNavigation.kt | 2 + .../ui/navigation/RootAppNavigation.kt | 20 +- .../screens/settingsScreen/SettingsScreen.kt | 89 +++---- .../settingsScreen/about/AboutScreen.kt | 238 ++++++++++++++++++ .../suggestionsScreen/SuggestedFlagsList.kt | 7 + .../suggestionsScreen/SuggestionsScreen.kt | 9 +- app/src/main/res/drawable/ic_github.xml | 6 + app/src/main/res/drawable/ic_info.xml | 5 + app/src/main/res/drawable/ic_reset_saved.xml | 5 + app/src/main/res/drawable/ic_telegram.xml | 4 + app/src/main/res/drawable/star_background.xml | 9 + 11 files changed, 341 insertions(+), 53 deletions(-) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt create mode 100644 app/src/main/res/drawable/ic_github.xml create mode 100644 app/src/main/res/drawable/ic_info.xml create mode 100644 app/src/main/res/drawable/ic_reset_saved.xml create mode 100644 app/src/main/res/drawable/ic_telegram.xml create mode 100644 app/src/main/res/drawable/star_background.xml diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index 689ebd01..58f8e1e5 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -64,6 +64,8 @@ internal sealed class ScreensDestination(var screenRoute: String) { } data object Settings : ScreensDestination("settings") + data object SettingsAbout : ScreensDestination("settingsAbout") + data object Packages : ScreensDestination("packages") data object Welcome : ScreensDestination("welcome") data object RootRequest : ScreensDestination("rootRequest") diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt index 3e1b71f4..e96f3121 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt @@ -2,6 +2,7 @@ package ua.polodarb.gmsflags.ui.navigation import android.content.Context import android.net.Uri +import android.util.Log import android.widget.Toast import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.material3.AlertDialog @@ -44,6 +45,7 @@ import ua.polodarb.gmsflags.ui.screens.firstStartScreens.WelcomeScreen import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.FlagChangeScreen import ua.polodarb.gmsflags.ui.screens.packagesScreen.PackagesScreen import ua.polodarb.gmsflags.ui.screens.settingsScreen.SettingsScreen +import ua.polodarb.gmsflags.ui.screens.settingsScreen.about.AboutScreen @OptIn(ExperimentalAnimationApi::class, InternalCoroutinesApi::class) @Composable @@ -171,9 +173,25 @@ internal fun RootAppNavigation( composable( route = ScreensDestination.Settings.screenRoute, enterTransition = { enterAnim(toLeft = true) }, - exitTransition = { exitAnim(toLeft = false) }, + exitTransition = { exitAnim(toLeft = true) }, + popEnterTransition = { enterAnim(toLeft = false) }, + popExitTransition = { exitAnim(toLeft = false) } ) { SettingsScreen( + onBackPressed = navController::navigateUp, + onResetFlagsClick = {}, + onResetSavedClick = {}, + onAboutClick = { + navController.navigate(ScreensDestination.SettingsAbout.screenRoute) + } + ) // TODO: Implement SettingsScreen + } + composable( + route = ScreensDestination.SettingsAbout.screenRoute, + enterTransition = { enterAnim(toLeft = true) }, + exitTransition = { exitAnim(toLeft = false) }, + ) { + AboutScreen( onBackPressed = navController::navigateUp ) // TODO: Implement SettingsScreen } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt index 9a34ac8b..19055404 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt @@ -1,7 +1,12 @@ package ua.polodarb.gmsflags.ui.screens.settingsScreen +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -10,6 +15,7 @@ import androidx.compose.foundation.selection.selectableGroup import androidx.compose.foundation.selection.toggleable import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -19,24 +25,34 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarColors import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.res.painterResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.ui.components.inserts.NotImplementedScreen @OptIn(ExperimentalMaterial3Api::class) @Composable fun SettingsScreen( - onBackPressed: () -> Unit + onBackPressed: () -> Unit, + onResetFlagsClick: () -> Unit, + onResetSavedClick: () -> Unit, + onAboutClick: () -> Unit ) { val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val context = LocalContext.current @@ -51,10 +67,10 @@ fun SettingsScreen( Text( "Settings", maxLines = 1, - overflow = TextOverflow.Ellipsis + overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.displaySmall ) }, - scrollBehavior = scrollBehavior, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( @@ -62,66 +78,41 @@ fun SettingsScreen( contentDescription = "Localized description" ) } - } + }, + modifier = Modifier.padding(horizontal = 8.dp) ) } } ) { it -> Column(modifier = Modifier.padding(it)) { Column { - NotImplementedScreen() -// SettingsContent() + SettingsItem(R.drawable.ic_reset, "Reset flags", "Reset all overridden flags", { }) + SettingsItem(R.drawable.ic_reset_saved, "Reset saved", "Reset all saved packages or flags", { }) + SettingsItem(R.drawable.ic_info, "About & support", "Useful information and resources", onAboutClick) } } } } @Composable -fun SettingsContent() { - - val (checkedState, onStateChange) = remember { mutableStateOf(true) } - val list = listOf("Google Services", "Google Play Store") - - list.forEach { - Row( - Modifier - .fillMaxWidth() - .height(56.dp) - .toggleable( - value = checkedState, - onValueChange = { onStateChange(!checkedState) }, - role = Role.Checkbox - ) - .padding(horizontal = 16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Checkbox( - checked = checkedState, - onCheckedChange = null // null recommended for accessibility with screenreaders - ) - Text( - text = it, - style = MaterialTheme.typography.bodyLarge, - modifier = Modifier.padding(start = 16.dp) - ) - } - } -} - -@Composable -fun SettingsLabel( - text: String +fun SettingsItem( + icon: Int, + headline: String, + description: String, + onItemClick: () -> Unit ) { Row( - modifier = Modifier - .fillMaxWidth() - .height(24.dp) + modifier = Modifier.fillMaxWidth().clickable { onItemClick() }, + verticalAlignment = Alignment.CenterVertically ) { - Text( - text = text, - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.primary, - modifier = Modifier.padding(start = 16.dp) - ) + Image(painter = painterResource(id = icon), contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant), + modifier = Modifier.padding(horizontal = 24.dp, vertical = 28.dp)) + Column( + modifier = Modifier.weight(1f) + ) { + Text(text = headline, fontSize = 20.sp) + Text(text = description, color = MaterialTheme.colorScheme.outline, fontSize = 15.sp) + } } } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt new file mode 100644 index 00000000..b8c67a85 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt @@ -0,0 +1,238 @@ +package ua.polodarb.gmsflags.ui.screens.settingsScreen.about + +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.rounded.Person +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItem +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.hapticfeedback.HapticFeedback +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import ua.polodarb.gmsflags.BuildConfig +import ua.polodarb.gmsflags.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AboutScreen( + onBackPressed: () -> Unit +) { + + val uriHandler = LocalUriHandler.current + + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = { Text(text = "About & Support") }, + navigationIcon = { + IconButton(onClick = onBackPressed) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Localized description" + ) + } + }, + ) + } + ) { + Box(modifier = Modifier.padding(top = it.calculateTopPadding())) { + AboutSettingsContent( + onDeveloperClick = { + uriHandler.openUri("https://github.com/polodarb") + }, + onGitHubClick = { + uriHandler.openUri("https://github.com/polodarb/GMS-Flags") + }, + onTelegramClick = { + uriHandler.openUri("https://t.me/gmsflags") + } + ) + } + } +} + +@Composable +fun AboutSettingsContent( + onDeveloperClick: () -> Unit, + onGitHubClick: () -> Unit, + onTelegramClick: () -> Unit +) { + + val haptic = LocalHapticFeedback.current + + Column { + Header(haptic) + SettingsAboutListInfo(onDeveloperClick, onGitHubClick, onTelegramClick, haptic) + } +} + +@Composable +fun Header( + haptic: HapticFeedback +) { + + var rotationState by remember { mutableStateOf(0f) } + + val rotationDegrees by animateFloatAsState( + targetValue = rotationState, + animationSpec = tween(durationMillis = 300), label = "" + ) + + val interactionSource = remember { MutableInteractionSource() } + + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .clickable( + interactionSource = interactionSource, + indication = null + ) { + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + rotationState += 15f + } + ) { + Box( + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = R.drawable.star_background), + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.secondaryContainer), + modifier = Modifier + .size(240.dp) + .graphicsLayer(rotationZ = rotationDegrees) + ) + Image( + painter = painterResource(id = R.drawable.ic_launcher_foreground), + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSecondaryContainer), + modifier = Modifier.size(292.dp) + ) + } + } + Text( + text = "GMS Flags", + fontWeight = FontWeight.Medium, + style = MaterialTheme.typography.headlineLarge + ) + SettingsAboutVersionBadge() + } +} + + +@Composable +fun SettingsAboutVersionBadge() { + Box( + modifier = Modifier + .padding(top = 20.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.secondary) + ) { + Text( + text = "v${BuildConfig.VERSION_NAME}", + fontWeight = FontWeight.Medium, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSecondary, + modifier = Modifier.padding(horizontal = 10.dp, vertical = 2.dp) + ) + } +} + +@Composable +fun SettingsAboutListInfo( + onDeveloperClick: () -> Unit, + onGitHubClick: () -> Unit, + onTelegramClick: () -> Unit, + haptic: HapticFeedback +) { + Column( + modifier = Modifier.padding(top = 36.dp, start = 8.dp) + ) { + ListItem( + headlineContent = { + Text(text = "Danyil Kobzar") + }, + leadingContent = { + Image(imageVector = Icons.Rounded.Person, contentDescription = null) + }, + overlineContent = { + Text(text = "Developer") + }, + modifier = Modifier.clickable { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + onDeveloperClick() + } + ) + ListItem( + headlineContent = { + Text(text = "Source code") + }, + leadingContent = { + Image( + painter = painterResource(id = R.drawable.ic_github), + contentDescription = null + ) + }, + overlineContent = { + Text(text = "GitHub") + }, + modifier = Modifier.clickable { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + onGitHubClick() + } + ) + ListItem( + headlineContent = { + Text(text = "Telegram channel") + }, + leadingContent = { + Image( + painter = painterResource(id = R.drawable.ic_telegram), + contentDescription = null + ) + }, + overlineContent = { + Text(text = "Support & updates") + }, + modifier = Modifier.clickable { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + onTelegramClick() + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestedFlagsList.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestedFlagsList.kt index 96468000..ac52561a 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestedFlagsList.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestedFlagsList.kt @@ -10,6 +10,13 @@ data class SuggestedFlag( object SuggestedFlagsList { val suggestedFlagsList = mutableListOf( + SuggestedFlag( + "Google Search Suggestions new design", + "Nail Sadykov", + listOf("45369077"), + "com.google.android.libraries.search.googleapp.device#com.google.android.googlequicksearchbox", + false + ), SuggestedFlag( "Proofreading mode in GBoard", "GApps Flags & Leaks", diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index 74919c61..e074e24d 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -85,12 +85,11 @@ fun SuggestionsScreen( val listState = rememberLazyListState() val expandedFab by remember { derivedStateOf { - listState.firstVisibleItemIndex == 0 + listState.firstVisibleItemIndex == 1 || listState.firstVisibleItemIndex == 0 } } Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), floatingActionButton = { Box( modifier = Modifier.offset(y = 12.dp) @@ -235,7 +234,11 @@ fun WarningBanner( mutableStateOf(isFirstStart) } - AnimatedVisibility(visible = visibility, enter = fadeIn(), exit = fadeOut() + shrinkVertically()) { + AnimatedVisibility( + visible = visibility, + enter = fadeIn(), + exit = fadeOut() + shrinkVertically() + ) { Box( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/res/drawable/ic_github.xml b/app/src/main/res/drawable/ic_github.xml new file mode 100644 index 00000000..00e46051 --- /dev/null +++ b/app/src/main/res/drawable/ic_github.xml @@ -0,0 +1,6 @@ + + + diff --git a/app/src/main/res/drawable/ic_info.xml b/app/src/main/res/drawable/ic_info.xml new file mode 100644 index 00000000..9bd4157f --- /dev/null +++ b/app/src/main/res/drawable/ic_info.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_reset_saved.xml b/app/src/main/res/drawable/ic_reset_saved.xml new file mode 100644 index 00000000..f1db94e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_reset_saved.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_telegram.xml b/app/src/main/res/drawable/ic_telegram.xml new file mode 100644 index 00000000..d3557665 --- /dev/null +++ b/app/src/main/res/drawable/ic_telegram.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/star_background.xml b/app/src/main/res/drawable/star_background.xml new file mode 100644 index 00000000..ec968fc7 --- /dev/null +++ b/app/src/main/res/drawable/star_background.xml @@ -0,0 +1,9 @@ + + + From 787c796259f84c8bd80e1df0a9a2ed770f9dac85 Mon Sep 17 00:00:00 2001 From: polodarb Date: Wed, 27 Sep 2023 21:20:04 +0300 Subject: [PATCH 14/24] Changed rotation logo value from 15f to 30f --- .../gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt index b8c67a85..69c85a31 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt @@ -123,7 +123,7 @@ fun Header( indication = null ) { haptic.performHapticFeedback(HapticFeedbackType.LongPress) - rotationState += 15f + rotationState += 30f } ) { Box( From 075a32f00a1a15b43b1a3db5bcfad503cd1d67fd Mon Sep 17 00:00:00 2001 From: polodarb Date: Wed, 27 Sep 2023 21:24:39 +0300 Subject: [PATCH 15/24] Fixed icon tint in DarkMode in Settings-About --- .../ui/screens/settingsScreen/about/AboutScreen.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt index 69c85a31..84f58fe9 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt @@ -188,7 +188,11 @@ fun SettingsAboutListInfo( Text(text = "Danyil Kobzar") }, leadingContent = { - Image(imageVector = Icons.Rounded.Person, contentDescription = null) + Image( + imageVector = Icons.Rounded.Person, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) + ) }, overlineContent = { Text(text = "Developer") @@ -205,7 +209,8 @@ fun SettingsAboutListInfo( leadingContent = { Image( painter = painterResource(id = R.drawable.ic_github), - contentDescription = null + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) ) }, overlineContent = { @@ -223,7 +228,8 @@ fun SettingsAboutListInfo( leadingContent = { Image( painter = painterResource(id = R.drawable.ic_telegram), - contentDescription = null + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) ) }, overlineContent = { From a046225564d81083d323605390068d681db989a7 Mon Sep 17 00:00:00 2001 From: polodarb Date: Wed, 27 Sep 2023 21:34:45 +0300 Subject: [PATCH 16/24] Changed logo offset in Settings-About --- .../ui/screens/settingsScreen/about/AboutScreen.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt index 84f58fe9..ead06780 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/about/AboutScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape @@ -31,6 +32,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.hapticfeedback.HapticFeedback @@ -141,7 +143,7 @@ fun Header( painter = painterResource(id = R.drawable.ic_launcher_foreground), contentDescription = null, colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSecondaryContainer), - modifier = Modifier.size(292.dp) + modifier = Modifier.size(292.dp).offset(x = 8.dp) ) } } @@ -191,7 +193,8 @@ fun SettingsAboutListInfo( Image( imageVector = Icons.Rounded.Person, contentDescription = null, - colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant) + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant), + modifier = Modifier.scale(1.1f) ) }, overlineContent = { From 9be542726e5356a1f6ef90be61640afc237fa053 Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 00:58:25 +0300 Subject: [PATCH 17/24] Implemented Settings - Reset flags --- .../ua/polodarb/gmsflags/IRootDatabase.aidl | 2 + .../data/databases/gms/RootDatabase.kt | 18 ++ .../gmsflags/data/repo/SettingsRepository.kt | 20 ++ .../polodarb/gmsflags/di/RepositoryModule.kt | 7 + .../polodarb/gmsflags/di/ViewModelsModule.kt | 7 + .../gmsflags/ui/navigation/AppNavigation.kt | 1 + .../ui/navigation/RootAppNavigation.kt | 27 +- .../screens/settingsScreen/SettingsScreen.kt | 2 +- .../settingsScreen/SettingsViewModel.kt | 23 ++ .../resetFlags/ResetFlagsScreen.kt | 241 ++++++++++++++++++ .../SuggestionScreenViewModel.kt | 2 +- .../suggestionsScreen/SuggestionsScreen.kt | 5 + .../res/drawable/img_settings_reset_flags.xml | 89 +++++++ 13 files changed, 440 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt create mode 100644 app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt create mode 100644 app/src/main/res/drawable/img_settings_reset_flags.xml diff --git a/app/src/main/aidl/ua/polodarb/gmsflags/IRootDatabase.aidl b/app/src/main/aidl/ua/polodarb/gmsflags/IRootDatabase.aidl index 5b19fd41..0ffbb1ec 100644 --- a/app/src/main/aidl/ua/polodarb/gmsflags/IRootDatabase.aidl +++ b/app/src/main/aidl/ua/polodarb/gmsflags/IRootDatabase.aidl @@ -21,6 +21,8 @@ interface IRootDatabase { String androidPackage(String pkgName); List getUsers(); + void deleteAllOverriddenFlagsFromGMS(); + void deleteAllOverriddenFlagsFromPlayStore(); void deleteRowByFlagName(String packageName, String name); void deleteOverriddenFlagByPackage(String packageName); diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/databases/gms/RootDatabase.kt b/app/src/main/java/ua/polodarb/gmsflags/data/databases/gms/RootDatabase.kt index 179e81bb..ec25ef05 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/databases/gms/RootDatabase.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/databases/gms/RootDatabase.kt @@ -71,6 +71,12 @@ class RootDatabase : RootService() { override fun getListByPackages(pkgName: String): List = this@RootDatabase.getListByPackages(pkgName) + override fun deleteAllOverriddenFlagsFromGMS() = + this@RootDatabase.deleteAllOverriddenFlagsFromGMS() + + override fun deleteAllOverriddenFlagsFromPlayStore() = + this@RootDatabase.deleteAllOverriddenFlagsFromPlayStore() + override fun deleteRowByFlagName(packageName: String, name: String) = this@RootDatabase.deleteRowByFlagName(packageName, name) @@ -171,6 +177,18 @@ class RootDatabase : RootService() { return androidPackage } + fun deleteAllOverriddenFlagsFromGMS() { + gmsDB.execSQL( + "DELETE FROM FlagOverrides;" + ) + } + + fun deleteAllOverriddenFlagsFromPlayStore() { + vendingDB.execSQL( + "DELETE FROM FlagOverrides;" + ) + } + fun deleteRowByFlagName( packageName: String, name: String diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt b/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt new file mode 100644 index 00000000..da4216ba --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt @@ -0,0 +1,20 @@ +package ua.polodarb.gmsflags.data.repo + +import android.content.Context +import ua.polodarb.gmsflags.GMSApplication + +class SettingsRepository( + private val context: Context +) { + + private val gmsApplication = context as GMSApplication + + fun deleteAllOverriddenFlagsFromGMS() { + gmsApplication.getRootDatabase().deleteAllOverriddenFlagsFromGMS() + } + + fun deleteAllOverriddenFlagsFromPlayStore() { + gmsApplication.getRootDatabase().deleteAllOverriddenFlagsFromPlayStore() + } + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt index c9357114..416ca00b 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt @@ -4,6 +4,7 @@ import org.koin.dsl.module import ua.polodarb.gmsflags.data.repo.AppsListRepository import ua.polodarb.gmsflags.data.repo.GmsDBRepository import ua.polodarb.gmsflags.data.repo.RoomDBRepository +import ua.polodarb.gmsflags.data.repo.SettingsRepository val repositoryModule = module { @@ -26,4 +27,10 @@ val repositoryModule = module { ) } + single { + SettingsRepository( + context = get() + ) + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt index 17eac8b8..f3c44882 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/ViewModelsModule.kt @@ -6,6 +6,7 @@ import ua.polodarb.gmsflags.ui.screens.appsScreen.AppsScreenViewModel import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.FlagChangeScreenViewModel import ua.polodarb.gmsflags.ui.screens.packagesScreen.PackagesScreenViewModel import ua.polodarb.gmsflags.ui.screens.savedScreen.SavedScreenViewModel +import ua.polodarb.gmsflags.ui.screens.settingsScreen.SettingsViewModel import ua.polodarb.gmsflags.ui.screens.suggestionsScreen.SuggestionScreenViewModel val viewModelsModule = module { @@ -43,4 +44,10 @@ val viewModelsModule = module { ) } + viewModel { + SettingsViewModel( + settingsRepository = get() + ) + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index 58f8e1e5..c717b43a 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -65,6 +65,7 @@ internal sealed class ScreensDestination(var screenRoute: String) { data object Settings : ScreensDestination("settings") data object SettingsAbout : ScreensDestination("settingsAbout") + data object SettingsResetFlags : ScreensDestination("settingsResetFlags") data object Packages : ScreensDestination("packages") data object Welcome : ScreensDestination("welcome") diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt index e96f3121..61ccc05d 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt @@ -46,6 +46,8 @@ import ua.polodarb.gmsflags.ui.screens.flagChangeScreen.FlagChangeScreen import ua.polodarb.gmsflags.ui.screens.packagesScreen.PackagesScreen import ua.polodarb.gmsflags.ui.screens.settingsScreen.SettingsScreen import ua.polodarb.gmsflags.ui.screens.settingsScreen.about.AboutScreen +import ua.polodarb.gmsflags.ui.screens.settingsScreen.resetFlags.ResetFlagsScreen +import ua.polodarb.gmsflags.ui.screens.settingsScreen.resetFlags.SettingsResetFlagsHeader @OptIn(ExperimentalAnimationApi::class, InternalCoroutinesApi::class) @Composable @@ -159,6 +161,8 @@ internal fun RootAppNavigation( isButtonLoading = isButtonLoading.value ) } + + // Flag change composable( route = ScreensDestination.FlagChange.createStringRoute(ScreensDestination.Packages.screenRoute), arguments = listOf(navArgument("flagChange") { type = NavType.StringType }), @@ -170,6 +174,8 @@ internal fun RootAppNavigation( packageName = Uri.decode(backStackEntry.arguments?.getString("flagChange")) ) } + + // Settings composable( route = ScreensDestination.Settings.screenRoute, enterTransition = { enterAnim(toLeft = true) }, @@ -179,13 +185,28 @@ internal fun RootAppNavigation( ) { SettingsScreen( onBackPressed = navController::navigateUp, - onResetFlagsClick = {}, + onResetFlagsClick = { + navController.navigate(ScreensDestination.SettingsResetFlags.screenRoute) + }, onResetSavedClick = {}, onAboutClick = { navController.navigate(ScreensDestination.SettingsAbout.screenRoute) } ) // TODO: Implement SettingsScreen } + + // Settings - Reset Flags + composable( + route = ScreensDestination.SettingsResetFlags.screenRoute, + enterTransition = { enterAnim(toLeft = true) }, + exitTransition = { exitAnim(toLeft = false) }, + ) { + ResetFlagsScreen( + onBackPressed = navController::navigateUp + ) + } + + // Settings - About & Support composable( route = ScreensDestination.SettingsAbout.screenRoute, enterTransition = { enterAnim(toLeft = true) }, @@ -193,8 +214,10 @@ internal fun RootAppNavigation( ) { AboutScreen( onBackPressed = navController::navigateUp - ) // TODO: Implement SettingsScreen + ) } + + // Packages list composable( route = ScreensDestination.Packages.screenRoute, enterTransition = { enterAnim(toLeft = true) }, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt index 19055404..eb8d8d9e 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt @@ -86,7 +86,7 @@ fun SettingsScreen( ) { it -> Column(modifier = Modifier.padding(it)) { Column { - SettingsItem(R.drawable.ic_reset, "Reset flags", "Reset all overridden flags", { }) + SettingsItem(R.drawable.ic_reset, "Reset flags", "Reset all overridden flags", onResetFlagsClick) SettingsItem(R.drawable.ic_reset_saved, "Reset saved", "Reset all saved packages or flags", { }) SettingsItem(R.drawable.ic_info, "About & support", "Useful information and resources", onAboutClick) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt new file mode 100644 index 00000000..f92481d1 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt @@ -0,0 +1,23 @@ +package ua.polodarb.gmsflags.ui.screens.settingsScreen + +import androidx.lifecycle.ViewModel +import ua.polodarb.gmsflags.data.repo.SettingsRepository + +class SettingsViewModel( + val settingsRepository: SettingsRepository +): ViewModel() { + + fun deleteAllOverriddenFlagsFromGMS() { + settingsRepository.deleteAllOverriddenFlagsFromGMS() + } + + fun deleteAllOverriddenFlagsFromPlayStore() { + settingsRepository.deleteAllOverriddenFlagsFromPlayStore() + } + + fun deleteAllOverriddenFlags() { + settingsRepository.deleteAllOverriddenFlagsFromGMS() + settingsRepository.deleteAllOverriddenFlagsFromPlayStore() + } + +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt new file mode 100644 index 00000000..249d1dec --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt @@ -0,0 +1,241 @@ +package ua.polodarb.gmsflags.ui.screens.settingsScreen.resetFlags + +import android.widget.Toast +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.outlined.Info +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import org.koin.androidx.compose.koinViewModel +import ua.polodarb.gmsflags.R +import ua.polodarb.gmsflags.ui.screens.settingsScreen.SettingsViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ResetFlagsScreen( + onBackPressed: () -> Unit +) { + + val viewModel = koinViewModel() + val context = LocalContext.current + val haptic = LocalHapticFeedback.current + + var showDialog by rememberSaveable { + mutableStateOf(false) + } + + var resetFlagsType by rememberSaveable { + mutableStateOf(SettingsResetFlagsType.NONE) + } + + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = { Text(text = "Reset flags") }, + navigationIcon = { + IconButton(onClick = onBackPressed) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Localized description" + ) + } + }, + ) + } + ) { + Column( + modifier = Modifier + .padding(top = it.calculateTopPadding()) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + SettingsResetFlagsHeader() + Spacer(modifier = Modifier.height(16.dp)) + SettingsResetFlagsButtons( + onGmsClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + resetFlagsType = SettingsResetFlagsType.GMS + showDialog = true + }, + onPlayStoreClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + resetFlagsType = SettingsResetFlagsType.PLAYSTORE + showDialog = true + }, + onResetAllClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + resetFlagsType = SettingsResetFlagsType.ALL + showDialog = true + } + ) + } + ConfirmResetFlagsDialog(showDialog = showDialog, onDismiss = { showDialog = false }) { + showDialog = false + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + + when (resetFlagsType) { + SettingsResetFlagsType.GMS -> viewModel.deleteAllOverriddenFlagsFromGMS() + SettingsResetFlagsType.PLAYSTORE -> viewModel.deleteAllOverriddenFlagsFromPlayStore() + SettingsResetFlagsType.ALL -> viewModel.deleteAllOverriddenFlags() + SettingsResetFlagsType.NONE -> {} + } + + Toast.makeText(context, "Done!", Toast.LENGTH_SHORT).show() + } + } +} + +@Composable +fun SettingsResetFlagsHeader() { + Column { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp) + .clip(RoundedCornerShape(24.dp)) + .background(MaterialTheme.colorScheme.surfaceContainer), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = R.drawable.img_settings_reset_flags), + contentDescription = null, + modifier = Modifier.padding(24.dp) + ) + } + Image( + imageVector = Icons.Outlined.Info, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant), + modifier = Modifier.padding(start = 24.dp, bottom = 12.dp, top = 24.dp) + ) + Text( + text = "Restore default settings and clears any user-customized (overridden) flags or preferences within the application, providing a clean slate for configuration.", + style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Medium, + modifier = Modifier.padding(horizontal = 24.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +@Composable +fun SettingsResetFlagsButtons( + onGmsClick: () -> Unit, + onPlayStoreClick: () -> Unit, + onResetAllClick: () -> Unit +) { + Column( + modifier = Modifier.padding(horizontal = 24.dp) + ) { + OutlinedButton( + onClick = onGmsClick, + modifier = Modifier.fillMaxWidth() + ) { + Text(text = "Reset flags in GMS Database") + } + OutlinedButton( + onClick = onPlayStoreClick, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Text(text = "Reset flags in Play Store Database") + } + Button( + onClick = onResetAllClick, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 24.dp) + ) { + Text(text = "Reset all overridden flags") + } + } +} + +@Composable +fun ConfirmResetFlagsDialog( + showDialog: Boolean, + onDismiss: () -> Unit, + onConfirmClick: () -> Unit +) { + if (showDialog) { + AlertDialog( + onDismissRequest = onDismiss, + icon = { + Image( + painter = painterResource(id = R.drawable.ic_force_stop), + contentDescription = null, + modifier = Modifier.size(36.dp), + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface) + ) + }, + title = { + Text(text = "Confirm action") + }, + text = { + Text( + text = "All flags that you changed will be reset!", + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) + }, + confirmButton = { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + OutlinedButton( + onClick = onDismiss + ) { + Text("Close") + } + Button( + onClick = onConfirmClick + ) { + Text("Confirm") + } + } + }, + ) + } +} + +enum class SettingsResetFlagsType { + NONE, GMS, PLAYSTORE, ALL +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt index c1b11602..eb4fcd3f 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionScreenViewModel.kt @@ -45,7 +45,7 @@ class SuggestionScreenViewModel( usersList.addAll(repository.getUsers()) } - private fun getAllOverriddenBoolFlags() { + fun getAllOverriddenBoolFlags() { viewModelScope.launch { withContext(Dispatchers.IO) { repository.getAllOverriddenBoolFlags().collect { uiState -> diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index e074e24d..90db73de 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -39,6 +39,7 @@ import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -89,6 +90,10 @@ fun SuggestionsScreen( } } + LaunchedEffect(Unit) { + viewModel.getAllOverriddenBoolFlags() + } + Scaffold( floatingActionButton = { Box( diff --git a/app/src/main/res/drawable/img_settings_reset_flags.xml b/app/src/main/res/drawable/img_settings_reset_flags.xml new file mode 100644 index 00000000..818a671f --- /dev/null +++ b/app/src/main/res/drawable/img_settings_reset_flags.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 5e111f270b36e76f5fce1fea22d444ee1a3bb0fd Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 19:12:35 +0300 Subject: [PATCH 18/24] Implemented Settings - Reset saved --- .../gmsflags/data/repo/SettingsRepository.kt | 16 +- .../polodarb/gmsflags/di/RepositoryModule.kt | 4 +- .../gmsflags/ui/navigation/AppNavigation.kt | 1 + .../ui/navigation/RootAppNavigation.kt | 16 +- .../screens/settingsScreen/SettingsScreen.kt | 2 +- .../settingsScreen/SettingsViewModel.kt | 31 +++ .../resetSaved/ResetSavedScreen.kt | 241 ++++++++++++++++++ .../suggestionsScreen/SuggestionsScreen.kt | 1 + .../res/drawable/img_settings_reset_saved.xml | 89 +++++++ 9 files changed, 397 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt create mode 100644 app/src/main/res/drawable/img_settings_reset_saved.xml diff --git a/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt b/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt index da4216ba..f7341778 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/data/repo/SettingsRepository.kt @@ -2,13 +2,18 @@ package ua.polodarb.gmsflags.data.repo import android.content.Context import ua.polodarb.gmsflags.GMSApplication +import ua.polodarb.gmsflags.data.databases.local.dao.FlagsDAO +import ua.polodarb.gmsflags.data.databases.local.dao.PackagesDAO class SettingsRepository( - private val context: Context + private val context: Context, + private val flagsDao: FlagsDAO, + private val packagesDAO: PackagesDAO ) { private val gmsApplication = context as GMSApplication + // GMS Database fun deleteAllOverriddenFlagsFromGMS() { gmsApplication.getRootDatabase().deleteAllOverriddenFlagsFromGMS() } @@ -17,4 +22,13 @@ class SettingsRepository( gmsApplication.getRootDatabase().deleteAllOverriddenFlagsFromPlayStore() } + // Local Database + suspend fun deleteAllSavedFlags() { + flagsDao.deleteAllSavedFlags() + } + + suspend fun deleteAllSavedPackages() { + packagesDAO.deleteAllSavedPackages() + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt index 416ca00b..18c3cb09 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/di/RepositoryModule.kt @@ -29,7 +29,9 @@ val repositoryModule = module { single { SettingsRepository( - context = get() + context = get(), + flagsDao = get(), + packagesDAO = get() ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt index c717b43a..8168173a 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/AppNavigation.kt @@ -66,6 +66,7 @@ internal sealed class ScreensDestination(var screenRoute: String) { data object Settings : ScreensDestination("settings") data object SettingsAbout : ScreensDestination("settingsAbout") data object SettingsResetFlags : ScreensDestination("settingsResetFlags") + data object SettingsResetSaved : ScreensDestination("settingsResetSaved") data object Packages : ScreensDestination("packages") data object Welcome : ScreensDestination("welcome") diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt index 61ccc05d..caab5833 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/navigation/RootAppNavigation.kt @@ -48,6 +48,7 @@ import ua.polodarb.gmsflags.ui.screens.settingsScreen.SettingsScreen import ua.polodarb.gmsflags.ui.screens.settingsScreen.about.AboutScreen import ua.polodarb.gmsflags.ui.screens.settingsScreen.resetFlags.ResetFlagsScreen import ua.polodarb.gmsflags.ui.screens.settingsScreen.resetFlags.SettingsResetFlagsHeader +import ua.polodarb.gmsflags.ui.screens.settingsScreen.resetSaved.ResetSavedScreen @OptIn(ExperimentalAnimationApi::class, InternalCoroutinesApi::class) @Composable @@ -188,7 +189,9 @@ internal fun RootAppNavigation( onResetFlagsClick = { navController.navigate(ScreensDestination.SettingsResetFlags.screenRoute) }, - onResetSavedClick = {}, + onResetSavedClick = { + navController.navigate(ScreensDestination.SettingsResetSaved.screenRoute) + }, onAboutClick = { navController.navigate(ScreensDestination.SettingsAbout.screenRoute) } @@ -206,6 +209,17 @@ internal fun RootAppNavigation( ) } + // Settings - Reset Saved + composable( + route = ScreensDestination.SettingsResetSaved.screenRoute, + enterTransition = { enterAnim(toLeft = true) }, + exitTransition = { exitAnim(toLeft = false) }, + ) { + ResetSavedScreen( + onBackPressed = navController::navigateUp + ) + } + // Settings - About & Support composable( route = ScreensDestination.SettingsAbout.screenRoute, diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt index eb8d8d9e..a74366ec 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsScreen.kt @@ -87,7 +87,7 @@ fun SettingsScreen( Column(modifier = Modifier.padding(it)) { Column { SettingsItem(R.drawable.ic_reset, "Reset flags", "Reset all overridden flags", onResetFlagsClick) - SettingsItem(R.drawable.ic_reset_saved, "Reset saved", "Reset all saved packages or flags", { }) + SettingsItem(R.drawable.ic_reset_saved, "Reset saved", "Reset all saved packages or flags", onResetSavedClick) SettingsItem(R.drawable.ic_info, "About & support", "Useful information and resources", onAboutClick) } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt index f92481d1..3edf987a 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/SettingsViewModel.kt @@ -1,12 +1,17 @@ package ua.polodarb.gmsflags.ui.screens.settingsScreen import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import ua.polodarb.gmsflags.data.repo.SettingsRepository class SettingsViewModel( val settingsRepository: SettingsRepository ): ViewModel() { + // GMS DATABASE fun deleteAllOverriddenFlagsFromGMS() { settingsRepository.deleteAllOverriddenFlagsFromGMS() } @@ -20,4 +25,30 @@ class SettingsViewModel( settingsRepository.deleteAllOverriddenFlagsFromPlayStore() } + // Local Room DATABASE + fun deleteAllSavedFlags() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + settingsRepository.deleteAllSavedFlags() + } + } + } + + fun deleteAllSavedPackages() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + settingsRepository.deleteAllSavedPackages() + } + } + } + + fun deleteAllSavedFlagsAndPackages() { + viewModelScope.launch { + withContext(Dispatchers.IO) { + settingsRepository.deleteAllSavedFlags() + settingsRepository.deleteAllSavedPackages() + } + } + } + } \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt new file mode 100644 index 00000000..3483e675 --- /dev/null +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt @@ -0,0 +1,241 @@ +package ua.polodarb.gmsflags.ui.screens.settingsScreen.resetSaved + +import android.widget.Toast +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.outlined.Info +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import org.koin.androidx.compose.koinViewModel +import ua.polodarb.gmsflags.R +import ua.polodarb.gmsflags.ui.screens.settingsScreen.SettingsViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ResetSavedScreen( + onBackPressed: () -> Unit +) { + + val viewModel = koinViewModel() + val context = LocalContext.current + val haptic = LocalHapticFeedback.current + + var showDialog by rememberSaveable { + mutableStateOf(false) + } + + var resetFlagsType by rememberSaveable { + mutableStateOf(SettingsResetSavedType.NONE) + } + + Scaffold( + topBar = { + CenterAlignedTopAppBar( + title = { Text(text = "Reset flags") }, + navigationIcon = { + IconButton(onClick = onBackPressed) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Localized description" + ) + } + }, + ) + } + ) { + Column( + modifier = Modifier + .padding(top = it.calculateTopPadding()) + .fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + SettingsResetFlagsHeader() + Spacer(modifier = Modifier.height(16.dp)) + SettingsResetFlagsButtons( + onPackagesClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + resetFlagsType = SettingsResetSavedType.PACKAGES + showDialog = true + }, + onFlagsClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + resetFlagsType = SettingsResetSavedType.FLAGS + showDialog = true + }, + onResetAllClick = { + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + resetFlagsType = SettingsResetSavedType.ALL + showDialog = true + } + ) + } + ConfirmResetFlagsDialog(showDialog = showDialog, onDismiss = { showDialog = false }) { + showDialog = false + haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) + + when (resetFlagsType) { + SettingsResetSavedType.PACKAGES -> viewModel.deleteAllSavedPackages() + SettingsResetSavedType.FLAGS -> viewModel.deleteAllSavedFlags() + SettingsResetSavedType.ALL -> viewModel.deleteAllSavedFlagsAndPackages() + SettingsResetSavedType.NONE -> {} + } + + Toast.makeText(context, "Done!", Toast.LENGTH_SHORT).show() + } + } +} + +@Composable +fun SettingsResetFlagsHeader() { + Column { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(24.dp) + .clip(RoundedCornerShape(24.dp)) + .background(MaterialTheme.colorScheme.surfaceContainer), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = R.drawable.img_settings_reset_saved), + contentDescription = null, + modifier = Modifier.padding(24.dp) + ) + } + Image( + imageVector = Icons.Outlined.Info, + contentDescription = null, + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant), + modifier = Modifier.padding(start = 24.dp, bottom = 12.dp, top = 24.dp) + ) + Text( + text = "In this section you can reset all packages and flags on the \"Saved\" screen that you have saved before.", + style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Medium, + modifier = Modifier.padding(horizontal = 24.dp), + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +@Composable +fun SettingsResetFlagsButtons( + onPackagesClick: () -> Unit, + onFlagsClick: () -> Unit, + onResetAllClick: () -> Unit +) { + Column( + modifier = Modifier.padding(horizontal = 24.dp) + ) { + OutlinedButton( + onClick = onPackagesClick, + modifier = Modifier.fillMaxWidth() + ) { + Text(text = "Reset saved packages") + } + OutlinedButton( + onClick = onFlagsClick, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Text(text = "Reset saved flags") + } + Button( + onClick = onResetAllClick, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 24.dp) + ) { + Text(text = "Reset all saved flags and packages") + } + } +} + +@Composable +fun ConfirmResetFlagsDialog( + showDialog: Boolean, + onDismiss: () -> Unit, + onConfirmClick: () -> Unit +) { + if (showDialog) { + AlertDialog( + onDismissRequest = onDismiss, + icon = { + Image( + painter = painterResource(id = R.drawable.ic_force_stop), + contentDescription = null, + modifier = Modifier.size(36.dp), + colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface) + ) + }, + title = { + Text(text = "Confirm action") + }, + text = { + Text( + text = "All flags that you saved will be reset!", + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) + }, + confirmButton = { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + OutlinedButton( + onClick = onDismiss + ) { + Text("Close") + } + Button( + onClick = onConfirmClick + ) { + Text("Confirm") + } + } + }, + ) + } +} + +enum class SettingsResetSavedType { + NONE, FLAGS, PACKAGES, ALL +} \ No newline at end of file diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index 90db73de..c86d4ae4 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -95,6 +95,7 @@ fun SuggestionsScreen( } Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), floatingActionButton = { Box( modifier = Modifier.offset(y = 12.dp) diff --git a/app/src/main/res/drawable/img_settings_reset_saved.xml b/app/src/main/res/drawable/img_settings_reset_saved.xml new file mode 100644 index 00000000..05aed5c9 --- /dev/null +++ b/app/src/main/res/drawable/img_settings_reset_saved.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e26a1bd1bd44908623fcffe2fe1e7e604fedab96 Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 19:28:42 +0300 Subject: [PATCH 19/24] Fixed dialog opening time in Apps-screen --- .../gmsflags/ui/screens/appsScreen/AppsScreen.kt | 16 ++++++++++++++-- .../ui/screens/appsScreen/AppsScreenViewModel.kt | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreen.kt index 1cad5152..fb834e7e 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -49,6 +50,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil.compose.AsyncImage +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.koin.androidx.compose.koinViewModel import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.data.AppInfo @@ -58,6 +62,7 @@ import ua.polodarb.gmsflags.ui.components.inserts.NoFlagsOrPackages import ua.polodarb.gmsflags.ui.components.searchBar.GFlagsSearchBar import ua.polodarb.gmsflags.ui.screens.appsScreen.dialog.AppsScreenDialog import ua.polodarb.gmsflags.ui.screens.appsScreen.dialog.DialogUiStates +import kotlin.coroutines.coroutineContext @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -76,6 +81,7 @@ fun AppsScreen( val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() val haptic = LocalHapticFeedback.current + val coroutineScope = rememberCoroutineScope() // Keyboard val focusRequester = remember { FocusRequester() } @@ -181,9 +187,13 @@ fun AppsScreen( pkg = item.applicationInfo.packageName, appIcon = item.icon, onClick = { - viewModel.getListByPackages(item.applicationInfo.packageName) - viewModel.setPackageToDialog(item.applicationInfo.packageName) showDialog.value = true + coroutineScope.launch { + withContext(Dispatchers.IO) { + viewModel.getListByPackages(item.applicationInfo.packageName) + viewModel.setPackageToDialog(item.applicationInfo.packageName) + } + } }) } item { @@ -201,6 +211,7 @@ fun AppsScreen( showDialog.value, onDismiss = { showDialog.value = false + viewModel.setEmptyList() dialogPackagesList.clear() }, pkgName = dialogPackageText.value, @@ -208,6 +219,7 @@ fun AppsScreen( onPackageClick = { onPackageItemClick(it) showDialog.value = false + viewModel.setEmptyList() } ) } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreenViewModel.kt index cc9b3a65..00a7d3fc 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/appsScreen/AppsScreenViewModel.kt @@ -43,6 +43,10 @@ class AppsScreenViewModel( _dialogPackage.value = pkgName } + fun setEmptyList() { + _dialogDataState.value = DialogUiStates.Success(emptyList()) + } + fun getListByPackages(pkgName: String) { viewModelScope.launch { withContext(Dispatchers.IO) { From 76425d16982a13faa9d7e765d3e16d030e1fbd41 Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 19:35:31 +0300 Subject: [PATCH 20/24] Fixed switch change time in Suggestions-screen --- .../suggestionsScreen/SuggestionsScreen.kt | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index c86d4ae4..942aa5f1 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -60,6 +60,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.koin.androidx.compose.koinViewModel import ua.polodarb.gmsflags.R import ua.polodarb.gmsflags.ui.components.inserts.ErrorLoadScreen @@ -177,12 +180,16 @@ fun SuggestionsScreen( senderName = item.flagSender, flagValue = item.flagValue, flagOnCheckedChange = { - viewModel.updateFlagValue(it, index) - viewModel.overrideFlag( - packageName = item.phenotypePackageName, - name = item.phenotypeFlagName, - boolVal = if (it) "1" else "0" - ) + coroutineScope.launch { + withContext(Dispatchers.IO) { + viewModel.updateFlagValue(it, index) + viewModel.overrideFlag( + packageName = item.phenotypePackageName, + name = item.phenotypeFlagName, + boolVal = if (it) "1" else "0" + ) + } + } } ) } From 29e5a6f2a95ce2c46c8c32850a8bea48da362cf9 Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 19:39:04 +0300 Subject: [PATCH 21/24] Changed margins between buttons in Settings --- .../ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt | 2 +- .../ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt index 249d1dec..b0ad9ef1 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetFlags/ResetFlagsScreen.kt @@ -173,7 +173,7 @@ fun SettingsResetFlagsButtons( onClick = onPlayStoreClick, modifier = Modifier .fillMaxWidth() - .padding(vertical = 16.dp) + .padding(vertical = 12.dp) ) { Text(text = "Reset flags in Play Store Database") } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt index 3483e675..326d508c 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/settingsScreen/resetSaved/ResetSavedScreen.kt @@ -68,7 +68,7 @@ fun ResetSavedScreen( Scaffold( topBar = { CenterAlignedTopAppBar( - title = { Text(text = "Reset flags") }, + title = { Text(text = "Reset saved") }, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( @@ -173,7 +173,7 @@ fun SettingsResetFlagsButtons( onClick = onFlagsClick, modifier = Modifier .fillMaxWidth() - .padding(vertical = 16.dp) + .padding(vertical = 12.dp) ) { Text(text = "Reset saved flags") } From 75f23744e6a358258dac4aef91fe63ca355d41ac Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 20:17:05 +0300 Subject: [PATCH 22/24] Added open app details settings screen --- .../components/dropDown/FlagChangeDropDown.kt | 12 ++++++++++++ .../flagChangeScreen/FlagChangeScreen.kt | 19 ++++++++++++++++++- .../FlagChangeScreenViewModel.kt | 4 ++++ .../res/drawable/ic_open_app_settings.xml | 5 +++++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_open_app_settings.xml diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/components/dropDown/FlagChangeDropDown.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/components/dropDown/FlagChangeDropDown.kt index c3b024b2..d8fc8b45 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/components/dropDown/FlagChangeDropDown.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/components/dropDown/FlagChangeDropDown.kt @@ -23,6 +23,7 @@ fun FlagChangeDropDown( onDismissRequest: () -> Unit, onAddFlag: () -> Unit, onDeleteOverriddenFlags: () -> Unit, + onOpenAppDetailsSettings: () -> Unit, modifier: Modifier = Modifier ) { Box( @@ -59,6 +60,17 @@ fun FlagChangeDropDown( }, enabled = true ) + DropdownMenuItem( + text = { Text(text = stringResource(R.string.open_app_details_settings)) }, + onClick = onOpenAppDetailsSettings, + leadingIcon = { + Icon( + painterResource(id = R.drawable.ic_open_app_settings), + contentDescription = null + ) + }, + enabled = true + ) } } } diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt index e1a1ea23..b3c34250 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreen.kt @@ -1,6 +1,9 @@ package ua.polodarb.gmsflags.ui.screens.flagChangeScreen import android.content.Context +import android.content.Intent +import android.net.Uri +import android.provider.Settings import android.util.Log import android.widget.Toast import androidx.compose.animation.AnimatedVisibility @@ -59,7 +62,10 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat.startActivity +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf import ua.polodarb.gmsflags.R @@ -169,6 +175,7 @@ fun FlagChangeScreen( focusRequester.requestFocus() } + val androidPackage = viewModel.getAndroidPackage(packageName.toString()) // DropDown menu var dropDownExpanded by remember { mutableStateOf(false) } @@ -269,6 +276,13 @@ fun FlagChangeScreen( dropDownExpanded = false Toast.makeText(context, "Done!", Toast.LENGTH_SHORT).show() }, + onOpenAppDetailsSettings = { + val intent = + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", androidPackage, null) + intent.setData(uri) + startActivity(context, intent, null) + }, modifier = Modifier .fillMaxWidth() .padding(8.dp) @@ -733,7 +747,10 @@ fun OtherTypesFlagsScreen( flagsType.name ) } else { - viewModel.deleteSavedFlag(item.first, packageName.toString()) + viewModel.deleteSavedFlag( + item.first, + packageName.toString() + ) } }, onClick = { diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt index e209c34e..c0b0f6a9 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/flagChangeScreen/FlagChangeScreenViewModel.kt @@ -106,6 +106,10 @@ class FlagChangeScreenViewModel( return filteredMap } + fun getAndroidPackage(pkgName: String): String { + return repository.androidPackage(pkgName) + } + private val changedFilterBoolList = mutableMapOf() private val usersList = mutableListOf() diff --git a/app/src/main/res/drawable/ic_open_app_settings.xml b/app/src/main/res/drawable/ic_open_app_settings.xml new file mode 100644 index 00000000..6cd2040f --- /dev/null +++ b/app/src/main/res/drawable/ic_open_app_settings.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db803a9d..e61e1745 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -40,4 +40,5 @@ Close Update GMS Flags "Finder: " + Open app details settings \ No newline at end of file From eb553ca7dcc20af497a8e41d8cb9c0af5359f24b Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 20:19:35 +0300 Subject: [PATCH 23/24] Updated app version to v1.0.4 --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4155b4af..4f22746d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "ua.polodarb.gmsflags" minSdk = 29 targetSdk = 33 - versionCode = 4 - versionName = "1.0.3" + versionCode = 5 + versionName = "1.0.4" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { From 71294a14fb7f893e2cf06cb8a98f58f99948d774 Mon Sep 17 00:00:00 2001 From: polodarb Date: Thu, 28 Sep 2023 20:21:16 +0300 Subject: [PATCH 24/24] Updated strings from "Not implemented" to "Coming soon" --- .../gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt | 2 +- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt index 942aa5f1..809c1189 100644 --- a/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt +++ b/app/src/main/java/ua/polodarb/gmsflags/ui/screens/suggestionsScreen/SuggestionsScreen.kt @@ -107,7 +107,7 @@ fun SuggestionsScreen( containerColor = MaterialTheme.colorScheme.secondaryContainer, onClick = { haptic.performHapticFeedback(HapticFeedbackType.TextHandleMove) - Toast.makeText(context, "Not implemented", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "Coming soon", Toast.LENGTH_SHORT).show() }, expanded = expandedFab, icon = { Icon(painterResource(id = R.drawable.ic_question), "") }, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e61e1745..0410d89b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,7 +32,7 @@ Data loading error Flags not found Apps not found - Not implemented + Coming soon Add flag Reset all overridden flags "Clicking the \"Update GMS Flags\" button will take you to GitHub with the latest release "