From 72b66227c0518c181a0b01f101b852b50e12af0d Mon Sep 17 00:00:00 2001 From: Mihai-Cristian Condrea Date: Tue, 23 Jul 2024 22:50:36 +0300 Subject: [PATCH] Improved the project readability and UI improvements to Image Optimizer --- CHANGELOG.md | 28 +- app/build.gradle.kts | 45 ++- .../d4rk/cleaner/ExampleInstrumentedTest.kt | 46 ++- .../kotlin/com/d4rk/cleaner/MainActivity.kt | 60 ++-- .../kotlin/com/d4rk/cleaner/MainComposable.kt | 166 ++++----- .../cleaner/constants/ads/AdsConstants.kt | 10 +- .../constants/cleaning/ExtensionsConstants.kt | 10 + .../d4rk/cleaner/data/core/AppCoreManager.kt | 84 ++--- .../d4rk/cleaner/data/datastore/DataStore.kt | 90 ++--- .../data/model/ui/appmanager/ui/ApkInfo.kt | 4 +- .../ui/imageoptimizer/CompressionLevel.kt | 6 +- .../ui/imageoptimizer/ImageOptimizerState.kt | 18 +- .../ui/memorymanager/InternalStorageInfo.kt | 4 +- .../data/model/ui/memorymanager/RamInfo.kt | 4 +- .../model/ui/memorymanager/StorageInfo.kt | 8 +- .../ui/navigation/BottomNavigationScreen.kt | 22 +- .../ui/navigation/NavigationDrawerItem.kt | 2 +- .../managers/AppUpdateNotificationsManager.kt | 32 +- .../managers/AppUsageNotificationsManager.kt | 10 +- .../receivers/AppUsageNotificationReceiver.kt | 2 +- .../workers/AppUsageNotificationWorker.kt | 24 +- .../appmanager/AppManagerViewModelFactory.kt | 8 +- .../ui/dialogs/LanguageDialogComposable.kt | 45 ++- .../ui/dialogs/RequireRestartDialog.kt | 26 +- .../ui/dialogs/RescanDialogComposable.kt | 31 +- .../ui/dialogs/VersionInfoDialogComposable.kt | 27 +- .../com/d4rk/cleaner/ui/help/HelpActivity.kt | 4 +- .../d4rk/cleaner/ui/help/HelpComposable.kt | 114 +++---- .../com/d4rk/cleaner/ui/help/HelpViewModel.kt | 17 +- .../d4rk/cleaner/ui/home/HomeComposable.kt | 314 +++++++++--------- .../com/d4rk/cleaner/ui/home/HomeViewModel.kt | 42 +-- .../imageoptimizer/ImageOptimizerActivity.kt | 10 +- .../ImageOptimizerComposable.kt | 150 ++++----- .../imageoptimizer/ImageOptimizerViewModel.kt | 58 ++-- .../imageoptimizer/tabs/FileSizeComposable.kt | 68 ++-- .../tabs/ManualModeComposable.kt | 51 ++- .../tabs/QuickCompressComposable.kt | 18 +- .../imagepicker/ImagePickerActivity.kt | 20 +- .../imagepicker/ImagePickerComposable.kt | 94 +++--- .../imagepicker/ImagePickerViewModel.kt | 4 +- .../ui/memory/MemoryManagerComposable.kt | 137 ++++---- .../ui/memory/MemoryManagerViewModel.kt | 25 +- .../cleaner/ui/settings/SettingsActivity.kt | 4 +- .../cleaner/ui/settings/SettingsComposable.kt | 105 +++--- .../settings/about/AboutSettingsComposable.kt | 29 +- .../advanced/AdvancedSettingsComposable.kt | 20 +- .../cleaning/CleaningSettingsActivity.kt | 4 +- .../cleaning/CleaningSettingsComposable.kt | 70 ++-- .../display/DisplaySettingsComposable.kt | 132 ++++---- .../display/theme/ThemeSettingsComposable.kt | 12 +- .../ui/settings/display/theme/style/Theme.kt | 8 +- .../ui/settings/display/theme/style/Type.kt | 8 +- .../privacy/PrivacySettingsComposable.kt | 129 +++---- .../privacy/ads/AdsSettingsComposable.kt | 48 +-- .../PermissionsSettingsComposable.kt | 106 +++--- .../usage/UsageAndDiagnosticsComposable.kt | 36 +- .../cleaner/ui/startup/StartupComposable.kt | 84 ++--- .../cleaner/ui/support/SupportActivity.kt | 9 +- .../cleaner/ui/support/SupportComposable.kt | 134 ++++---- .../cleaner/ui/support/SupportViewModel.kt | 16 +- .../d4rk/cleaner/utils/PermissionsUtils.kt | 86 +++-- .../cleaner/utils/cleaning/FileScanner.kt | 105 +++--- .../d4rk/cleaner/utils/cleaning/FileUtils.kt | 9 +- .../d4rk/cleaner/utils/cleaning/ImageUtils.kt | 24 +- .../cleaner/utils/compose/AnimationUtils.kt | 34 +- .../components/ProgressBarsComposables.kt | 51 ++- .../components/SettingsComposablesUtils.kt | 72 ++-- .../imageoptimizer/ImageOptimizerUtils.kt | 2 +- app/src/main/res/values-ro/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/config_locales.xml | 2 +- .../com/d4rk/cleaner/ExampleUnitTest.kt | 2 +- gradle/libs.versions.toml | 2 +- 75 files changed, 1643 insertions(+), 1642 deletions(-) create mode 100644 app/src/main/kotlin/com/d4rk/cleaner/constants/cleaning/ExtensionsConstants.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 249a30e..f562e8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,26 @@ # Version 2.0.0: -- **New**: Added a progress bar to the main screen, offering an approximate visualization of storage usage. -- **New**: Users can now select specific files for deletion after the scan completes, allowing for granular control. -- **New**: Enhanced the post-scan screen to display previews of images and videos, aiding in file selection. -- **New**: Introduced the option to select all files for deletion, streamlining the cleaning process. -- **New**: Completely overhauled the memory manager, now showcasing storage usage categorized by file types. -- **New**: Added support for dynamic colors on compatible devices, allowing the app to adapt to system-wide color palettes. + +- **New**: Added a progress bar to the main screen, offering an approximate visualization of storage + usage. +- **New**: Users can now select specific files for deletion after the scan completes, allowing for + granular control. +- **New**: Enhanced the post-scan screen to display previews of images and videos, aiding in file + selection. +- **New**: Introduced the option to select all files for deletion, streamlining the cleaning + process. +- **New**: Completely overhauled the memory manager, now showcasing storage usage categorized by + file types. +- **New**: Added support for dynamic colors on compatible devices, allowing the app to adapt to + system-wide color palettes. - **New**: Refined the AMOLED theme for a more immersive dark mode experience. - **New**: Incorporated updated translations thanks to valuable contributions from the community. - **New**: Introduced a dedicated section for managing security and privacy settings within the app. -- **New**: Implemented new animations and improved overall app responsiveness for a smoother user experience. -- **Major**: Migrated the entire app to Jetpack Compose, providing a modern and improved user interface. -- **Major**: Completely reworked the app's logic using view models and coroutines for enhanced performance and maintainability. +- **New**: Implemented new animations and improved overall app responsiveness for a smoother user + experience. +- **Major**: Migrated the entire app to Jetpack Compose, providing a modern and improved user + interface. +- **Major**: Completely reworked the app's logic using view models and coroutines for enhanced + performance and maintainability. # Version 1.1.0: diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c7c7788..a90f8b2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,27 +14,27 @@ android { applicationId = "com.d4rk.cleaner" minSdk = 26 targetSdk = 34 - versionCode = 96 + versionCode = 97 versionName = "2.0.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" resourceConfigurations += listOf( - "en", - "de", - "es", - "fr", - "hi", - "hu", - "in", - "it", - "ja", - "ro", - "ru", - "tr", - "sv", - "bg", - "pl", - "uk", - "b+zh+rTW", + "en" , + "de" , + "es" , + "fr" , + "hi" , + "hu" , + "in" , + "it" , + "ja" , + "ro" , + "ru" , + "tr" , + "sv" , + "bg" , + "pl" , + "uk" , + "b+zh+rTW" , ) vectorDrawables { useSupportLibrary = true @@ -49,8 +49,7 @@ android { isDebuggable = false versionNameSuffix = null proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" + getDefaultProguardFile("proguard-android-optimize.txt") , "proguard-rules.pro" ) } debug { @@ -58,8 +57,7 @@ android { isDebuggable = true versionNameSuffix = null proguardFiles( - getDefaultProguardFile("proguard-android-optimize.txt"), - "proguard-rules.pro" + getDefaultProguardFile("proguard-android-optimize.txt") , "proguard-rules.pro" ) } } @@ -73,7 +71,6 @@ android { } buildFeatures { - viewBinding = true buildConfig = true compose = true } @@ -150,7 +147,7 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) - androidTestImplementation(libs.androidx.ui.test.junit4) + androidTestImplementation(libs.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) } \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/d4rk/cleaner/ExampleInstrumentedTest.kt b/app/src/androidTest/kotlin/com/d4rk/cleaner/ExampleInstrumentedTest.kt index 80b2de9..a4a9369 100644 --- a/app/src/androidTest/kotlin/com/d4rk/cleaner/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/kotlin/com/d4rk/cleaner/ExampleInstrumentedTest.kt @@ -17,14 +17,14 @@ import java.io.File */ @RunWith(AndroidJUnit4::class) class ExampleInstrumentedTest { - private lateinit var fileScanner: FileScanner + private lateinit var fileScanner : FileScanner @Before fun init() { val appContext = InstrumentationRegistry.getInstrumentation().targetContext - val path = File(Environment.getExternalStorageDirectory(), "") + val path = File(Environment.getExternalStorageDirectory() , "") val res = appContext.resources - fileScanner = FileScanner(path, appContext).apply { + fileScanner = FileScanner(path , appContext).apply { setAutoWhite(false) setResources(res) setDelete(true) @@ -34,14 +34,19 @@ class ExampleInstrumentedTest { @Test fun useAppContext() { val appContext = InstrumentationRegistry.getInstrumentation().targetContext - Assert.assertEquals("com.d4rk.cleaner", appContext.packageName) + Assert.assertEquals("com.d4rk.cleaner" , appContext.packageName) } @Test fun checkLogFiles() { val logFile = createFile("testfile.loG") val clogFile = createFile("clogs.pnG") - fileScanner.setUpFilters(generic = true, aggressive = false, apk = false, archive = false) + fileScanner.setUpFilters( + generic = true , + aggressive = false , + apk = false , + archive = false + ) fileScanner.startScan() Assert.assertTrue(clogFile.exists()) Assert.assertFalse(logFile.exists()) @@ -50,7 +55,12 @@ class ExampleInstrumentedTest { @Test fun checkTempFiles() { val tmpFile = createFile("testfile.tMp") - fileScanner.setUpFilters(generic = true, aggressive = false, apk = false, archive = false) + fileScanner.setUpFilters( + generic = true , + aggressive = false , + apk = false , + archive = false + ) fileScanner.startScan() Assert.assertFalse(tmpFile.exists()) } @@ -58,7 +68,12 @@ class ExampleInstrumentedTest { @Test fun checkThumbFiles() { val thumbFile = createFile("thumbs.Db") - fileScanner.setUpFilters(generic = false, aggressive = true, apk = false, archive = false) + fileScanner.setUpFilters( + generic = false , + aggressive = true , + apk = false , + archive = false + ) fileScanner.startScan() Assert.assertFalse(thumbFile.exists()) } @@ -66,7 +81,7 @@ class ExampleInstrumentedTest { @Test fun checkAPKFiles() { val thumbFile = createFile("chrome.aPk") - fileScanner.setUpFilters(generic = true, aggressive = true, apk = true, archive = false) + fileScanner.setUpFilters(generic = true , aggressive = true , apk = true , archive = false) fileScanner.startScan() Assert.assertFalse(thumbFile.exists()) } @@ -74,14 +89,19 @@ class ExampleInstrumentedTest { @Test fun checkEmptyDir() { val emptyDir = createDir() - fileScanner.setUpFilters(generic = true, aggressive = false, apk = false, archive = false) + fileScanner.setUpFilters( + generic = true , + aggressive = false , + apk = false , + archive = false + ) fileScanner.setEmptyDir(true) fileScanner.startScan() Assert.assertFalse(emptyDir.exists()) } - private fun createFile(name: String): File { - val file = File(Environment.getExternalStorageDirectory(), name) + private fun createFile(name : String) : File { + val file = File(Environment.getExternalStorageDirectory() , name) file.createNewFile().let { Assert.assertTrue(it) } @@ -89,8 +109,8 @@ class ExampleInstrumentedTest { return file } - private fun createDir(): File { - val file = File(Environment.getExternalStorageDirectory(), "testdir") + private fun createDir() : File { + val file = File(Environment.getExternalStorageDirectory() , "testdir") file.mkdir().let { Assert.assertTrue(it) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/MainActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/MainActivity.kt index 51b48d5..af63526 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/MainActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/MainActivity.kt @@ -33,12 +33,12 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.tasks.await class MainActivity : AppCompatActivity() { - private lateinit var dataStore: DataStore - private lateinit var appUpdateManager: AppUpdateManager - private var appUpdateNotificationsManager: AppUpdateNotificationsManager = - AppUpdateNotificationsManager(this) + private lateinit var dataStore : DataStore + private lateinit var appUpdateManager : AppUpdateManager + private var appUpdateNotificationsManager : AppUpdateNotificationsManager = + AppUpdateNotificationsManager(this) - override fun onCreate(savedInstanceState: Bundle?) { + override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) installSplashScreen() enableEdgeToEdge() @@ -49,7 +49,7 @@ class MainActivity : AppCompatActivity() { setContent { AppTheme { Surface( - modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background + modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { MainComposable() } @@ -79,15 +79,11 @@ class MainActivity : AppCompatActivity() { @Deprecated("Deprecated in Java") @Suppress("DEPRECATION") override fun onBackPressed() { - MaterialAlertDialogBuilder(this) - .setTitle(R.string.close) - .setMessage(R.string.summary_close) - .setPositiveButton(android.R.string.yes) { _, _ -> - super.onBackPressed() - moveTaskToBack(true) - } - .setNegativeButton(android.R.string.no, null) - .apply { show() } + MaterialAlertDialogBuilder(this).setTitle(R.string.close).setMessage(R.string.summary_close) + .setPositiveButton(android.R.string.yes) { _ , _ -> + super.onBackPressed() + moveTaskToBack(true) + }.setNegativeButton(android.R.string.no , null).apply { show() } } /** @@ -104,16 +100,16 @@ class MainActivity : AppCompatActivity() { * @param data An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). */ @Deprecated("Deprecated in Java") - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) + override fun onActivityResult(requestCode : Int , resultCode : Int , data : Intent?) { + super.onActivityResult(requestCode , resultCode , data) if (requestCode == 1) { when (resultCode) { RESULT_OK -> { val snackbar = Snackbar.make( - findViewById(android.R.id.content), - R.string.snack_app_updated, + findViewById(android.R.id.content) , + R.string.snack_app_updated , Snackbar.LENGTH_LONG - ).setAction(android.R.string.ok, null) + ).setAction(android.R.string.ok , null) snackbar.show() } @@ -154,7 +150,7 @@ class MainActivity : AppCompatActivity() { info.clientVersionStalenessDays()?.let { if (it > 90) { appUpdateManager.startUpdateFlowForResult( - info, AppUpdateType.IMMEDIATE, this@MainActivity, 1 + info , AppUpdateType.IMMEDIATE , this@MainActivity , 1 ) } } @@ -166,7 +162,7 @@ class MainActivity : AppCompatActivity() { info.clientVersionStalenessDays()?.let { if (it < 90) { appUpdateManager.startUpdateFlowForResult( - info, AppUpdateType.FLEXIBLE, this@MainActivity, 1 + info , AppUpdateType.FLEXIBLE , this@MainActivity , 1 ) } } @@ -174,21 +170,21 @@ class MainActivity : AppCompatActivity() { } } } - } catch (e: Exception) { - if (!BuildConfig.DEBUG) { + } catch (e : Exception) { + if (! BuildConfig.DEBUG) { when (e) { - is NoConnectionError, is TimeoutError -> { + is NoConnectionError , is TimeoutError -> { Snackbar.make( - findViewById(android.R.id.content), - getString(R.string.snack_network_error), + findViewById(android.R.id.content) , + getString(R.string.snack_network_error) , Snackbar.LENGTH_LONG ).show() } else -> { Snackbar.make( - findViewById(android.R.id.content), - getString(R.string.snack_general_error), + findViewById(android.R.id.content) , + getString(R.string.snack_general_error) , Snackbar.LENGTH_LONG ).show() } @@ -207,7 +203,7 @@ class MainActivity : AppCompatActivity() { */ private fun showUpdateFailedSnackbar() { val snackbar = Snackbar.make( - findViewById(android.R.id.content), R.string.snack_update_failed, Snackbar.LENGTH_LONG + findViewById(android.R.id.content) , R.string.snack_update_failed , Snackbar.LENGTH_LONG ).setAction(R.string.try_again) { checkForFlexibleUpdate() } @@ -236,7 +232,7 @@ class MainActivity : AppCompatActivity() { lifecycleScope.launch { val isEnabled = dataStore.usageAndDiagnostics.first() FirebaseAnalytics.getInstance(this@MainActivity) - .setAnalyticsCollectionEnabled(isEnabled) + .setAnalyticsCollectionEnabled(isEnabled) FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(isEnabled) } } @@ -245,7 +241,7 @@ class MainActivity : AppCompatActivity() { lifecycleScope.launch { if (dataStore.startup.first()) { dataStore.saveStartup(false) - startActivity(Intent(this@MainActivity, StartupActivity::class.java)) + startActivity(Intent(this@MainActivity , StartupActivity::class.java)) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/MainComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/MainComposable.kt index 69c1d32..1f50159 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/MainComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/MainComposable.kt @@ -60,91 +60,92 @@ import kotlinx.coroutines.launch @Composable fun MainComposable() { val bottomBarItems = listOf( - BottomNavigationScreen.Home, BottomNavigationScreen.AppManager, BottomNavigationScreen.MemoryManager + BottomNavigationScreen.Home , + BottomNavigationScreen.AppManager , + BottomNavigationScreen.MemoryManager ) val drawerItems = listOf( NavigationDrawerItem( - title = R.string.image_optimizer, selectedIcon = Icons.Outlined.Image - ), + title = R.string.image_optimizer , selectedIcon = Icons.Outlined.Image + ) , NavigationDrawerItem( - title = R.string.settings, - selectedIcon = Icons.Outlined.Settings, - ), + title = R.string.settings , + selectedIcon = Icons.Outlined.Settings , + ) , NavigationDrawerItem( - title = R.string.help_and_feedback, - selectedIcon = Icons.AutoMirrored.Outlined.HelpOutline, - ), + title = R.string.help_and_feedback , + selectedIcon = Icons.AutoMirrored.Outlined.HelpOutline , + ) , NavigationDrawerItem( - title = R.string.updates, - selectedIcon = Icons.AutoMirrored.Outlined.EventNote, - ), + title = R.string.updates , + selectedIcon = Icons.AutoMirrored.Outlined.EventNote , + ) , NavigationDrawerItem( - title = R.string.share, selectedIcon = Icons.Outlined.Share - ), + title = R.string.share , selectedIcon = Icons.Outlined.Share + ) , ) val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val scope = rememberCoroutineScope() val navController = rememberNavController() val context = LocalContext.current val dataStore = DataStore.getInstance(context) - val selectedItemIndex by rememberSaveable { mutableIntStateOf(-1) } - ModalNavigationDrawer(drawerState = drawerState, drawerContent = { + val selectedItemIndex by rememberSaveable { mutableIntStateOf(- 1) } + ModalNavigationDrawer(drawerState = drawerState , drawerContent = { ModalDrawerSheet { Spacer(modifier = Modifier.height(16.dp)) - drawerItems.forEachIndexed { index, item -> + drawerItems.forEachIndexed { index , item -> val title = stringResource(item.title) - NavigationDrawerItem( - label = { Text(text = title) }, - selected = index == selectedItemIndex, - onClick = { - when (item.title) { + NavigationDrawerItem(label = { Text(text = title) } , + selected = index == selectedItemIndex , + onClick = { + when (item.title) { - R.string.image_optimizer -> { - IntentUtils.openActivity( - context, ImagePickerActivity::class.java - ) - } + R.string.image_optimizer -> { + IntentUtils.openActivity( + context , ImagePickerActivity::class.java + ) + } - R.string.settings -> { - IntentUtils.openActivity( - context, SettingsActivity::class.java - ) - } + R.string.settings -> { + IntentUtils.openActivity( + context , SettingsActivity::class.java + ) + } - R.string.help_and_feedback -> { - IntentUtils.openActivity( - context, HelpActivity::class.java - ) - } + R.string.help_and_feedback -> { + IntentUtils.openActivity( + context , HelpActivity::class.java + ) + } - R.string.updates -> { - IntentUtils.openUrl( - context, - "https://github.com/D4rK7355608/${context.packageName}/blob/master/CHANGELOG.md" - ) - } + R.string.updates -> { + IntentUtils.openUrl( + context , + "https://github.com/D4rK7355608/${context.packageName}/blob/master/CHANGELOG.md" + ) + } - R.string.share -> { - IntentUtils.shareApp(context) - } - } - scope.launch { - drawerState.close() - } - }, - icon = { - Icon( - item.selectedIcon, contentDescription = title - ) - }, - badge = { - item.badgeCount?.let { - Text(text = item.badgeCount.toString()) - } - }, - modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding) + R.string.share -> { + IntentUtils.shareApp(context) + } + } + scope.launch { + drawerState.close() + } + } , + icon = { + Icon( + item.selectedIcon , contentDescription = title + ) + } , + badge = { + item.badgeCount?.let { + Text(text = item.badgeCount.toString()) + } + } , + modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding) ) if (item.title == R.string.image_optimizer) { HorizontalDivider(modifier = Modifier.padding(8.dp)) @@ -152,11 +153,11 @@ fun MainComposable() { } } - }, content = { + } , content = { Scaffold(topBar = { TopAppBar(title = { Text(text = stringResource(R.string.app_name)) - }, navigationIcon = { + } , navigationIcon = { IconButton(onClick = { scope.launch { drawerState.apply { @@ -165,44 +166,45 @@ fun MainComposable() { } }) { Icon( - imageVector = Icons.Default.Menu, contentDescription = stringResource(id = R.string.navigation_drawer_open) + imageVector = Icons.Default.Menu , + contentDescription = stringResource(id = R.string.navigation_drawer_open) ) } - }, actions = { + } , actions = { IconButton(onClick = { - IntentUtils.openActivity(context, SupportActivity::class.java) + IntentUtils.openActivity(context , SupportActivity::class.java) }) { Icon( - Icons.Outlined.VolunteerActivism, + Icons.Outlined.VolunteerActivism , contentDescription = stringResource(id = R.string.support_us) ) } }) - }, bottomBar = { + } , bottomBar = { Column { - FullBannerAdsComposable(modifier = Modifier.fillMaxWidth(), dataStore = dataStore) + FullBannerAdsComposable(modifier = Modifier.fillMaxWidth() , dataStore = dataStore) NavigationBar { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route bottomBarItems.forEach { screen -> NavigationBarItem(icon = { val iconResource = - if (currentRoute == screen.route) screen.selectedIcon else screen.icon - Icon(iconResource, contentDescription = null) - }, - label = { Text(stringResource(screen.title)) }, - selected = currentRoute == screen.route, - onClick = { - navController.navigate(screen.route) { - popUpTo(navController.graph.startDestinationId) - launchSingleTop = true - } - }) + if (currentRoute == screen.route) screen.selectedIcon else screen.icon + Icon(iconResource , contentDescription = null) + } , + label = { Text(stringResource(screen.title)) } , + selected = currentRoute == screen.route , + onClick = { + navController.navigate(screen.route) { + popUpTo(navController.graph.startDestinationId) + launchSingleTop = true + } + }) } } } }) { innerPadding -> - NavHost(navController, startDestination = BottomNavigationScreen.Home.route) { + NavHost(navController , startDestination = BottomNavigationScreen.Home.route) { composable(BottomNavigationScreen.Home.route) { Box(modifier = Modifier.padding(innerPadding)) { HomeComposable() diff --git a/app/src/main/kotlin/com/d4rk/cleaner/constants/ads/AdsConstants.kt b/app/src/main/kotlin/com/d4rk/cleaner/constants/ads/AdsConstants.kt index c2c9f0e..7f3fd18 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/constants/ads/AdsConstants.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/constants/ads/AdsConstants.kt @@ -4,17 +4,19 @@ import com.d4rk.cleaner.BuildConfig object AdsConstants { - val BANNER_AD_UNIT_ID: String + val BANNER_AD_UNIT_ID : String get() = if (BuildConfig.DEBUG) { "ca-app-pub-3940256099942544/6300978111" - } else { + } + else { "ca-app-pub-5294151573817700/8040893463" } - val APP_OPEN_UNIT_ID: String + val APP_OPEN_UNIT_ID : String get() = if (BuildConfig.DEBUG) { "ca-app-pub-3940256099942544/9257395921" - } else { + } + else { "ca-app-pub-5294151573817700/9208287867" } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/constants/cleaning/ExtensionsConstants.kt b/app/src/main/kotlin/com/d4rk/cleaner/constants/cleaning/ExtensionsConstants.kt new file mode 100644 index 0000000..121c58d --- /dev/null +++ b/app/src/main/kotlin/com/d4rk/cleaner/constants/cleaning/ExtensionsConstants.kt @@ -0,0 +1,10 @@ +package com.d4rk.cleaner.constants.cleaning + +object ExtensionsConstants { + const val GENERIC_EXTENSIONS = "generic_extensions" + const val ARCHIVE_EXTENSIONS = "archive_extensions" + const val APK_EXTENSIONS = "apk_extensions" + const val IMAGE_EXTENSIONS = "image_extensions" + const val AUDIO_EXTENSIONS = "audio_extensions" + const val VIDEO_EXTENSIONS = "video_extensions" +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/core/AppCoreManager.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/core/AppCoreManager.kt index 323d5a3..6112af8 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/core/AppCoreManager.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/core/AppCoreManager.kt @@ -25,11 +25,11 @@ import kotlinx.coroutines.runBlocking import java.util.Date @Suppress("SameParameterValue") -class AppCoreManager : MultiDexApplication(), Application.ActivityLifecycleCallbacks, +class AppCoreManager : MultiDexApplication() , Application.ActivityLifecycleCallbacks , LifecycleObserver { - private lateinit var appOpenAdManager: AppOpenAdManager - private var currentActivity: Activity? = null - private lateinit var dataStore: DataStore + private lateinit var appOpenAdManager : AppOpenAdManager + private var currentActivity : Activity? = null + private lateinit var dataStore : DataStore override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(this) @@ -46,18 +46,18 @@ class AppCoreManager : MultiDexApplication(), Application.ActivityLifecycleCallb currentActivity?.let { appOpenAdManager.showAdIfAvailable(it) } } - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} - override fun onActivityStarted(activity: Activity) { - if (!appOpenAdManager.isShowingAd) { + override fun onActivityCreated(activity : Activity , savedInstanceState : Bundle?) {} + override fun onActivityStarted(activity : Activity) { + if (! appOpenAdManager.isShowingAd) { currentActivity = activity } } - override fun onActivityResumed(activity: Activity) {} - override fun onActivityPaused(activity: Activity) {} - override fun onActivityStopped(activity: Activity) {} - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} - override fun onActivityDestroyed(activity: Activity) {} + override fun onActivityResumed(activity : Activity) {} + override fun onActivityPaused(activity : Activity) {} + override fun onActivityStopped(activity : Activity) {} + override fun onActivitySaveInstanceState(activity : Activity , outState : Bundle) {} + override fun onActivityDestroyed(activity : Activity) {} interface OnShowAdCompleteListener { @Suppress("EmptyMethod") @@ -65,65 +65,65 @@ class AppCoreManager : MultiDexApplication(), Application.ActivityLifecycleCallb } private inner class AppOpenAdManager { - private var appOpenAd: AppOpenAd? = null + private var appOpenAd : AppOpenAd? = null private var isLoadingAd = false var isShowingAd = false - private var loadTime: Long = 0 + private var loadTime : Long = 0 - fun loadAd(context: Context) { + fun loadAd(context : Context) { if (isLoadingAd || isAdAvailable()) { return } isLoadingAd = true val request = AdRequest.Builder().build() - AppOpenAd.load(context, - AdsConstants.APP_OPEN_UNIT_ID, - request, - AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT, - object : AppOpenAd.AppOpenAdLoadCallback() { - override fun onAdLoaded(ad: AppOpenAd) { - appOpenAd = ad - isLoadingAd = false - loadTime = Date().time - } - - override fun onAdFailedToLoad(loadAdError: LoadAdError) { - isLoadingAd = false - } - }) + AppOpenAd.load(context , + AdsConstants.APP_OPEN_UNIT_ID , + request , + AppOpenAd.APP_OPEN_AD_ORIENTATION_PORTRAIT , + object : AppOpenAd.AppOpenAdLoadCallback() { + override fun onAdLoaded(ad : AppOpenAd) { + appOpenAd = ad + isLoadingAd = false + loadTime = Date().time + } + + override fun onAdFailedToLoad(loadAdError : LoadAdError) { + isLoadingAd = false + } + }) } - private fun wasLoadTimeLessThanNHoursAgo(numHours: Long): Boolean { - val dateDifference: Long = Date().time - loadTime - val numMilliSecondsPerHour: Long = 3600000 + private fun wasLoadTimeLessThanNHoursAgo(numHours : Long) : Boolean { + val dateDifference : Long = Date().time - loadTime + val numMilliSecondsPerHour : Long = 3600000 return dateDifference < numMilliSecondsPerHour * numHours } @Suppress("BooleanMethodIsAlwaysInverted") - private fun isAdAvailable(): Boolean { + private fun isAdAvailable() : Boolean { return appOpenAd != null && wasLoadTimeLessThanNHoursAgo(4) } - fun showAdIfAvailable(activity: Activity) { - showAdIfAvailable(activity, object : OnShowAdCompleteListener { + fun showAdIfAvailable(activity : Activity) { + showAdIfAvailable(activity , object : OnShowAdCompleteListener { override fun onShowAdComplete() { } }) } fun showAdIfAvailable( - activity: Activity, onShowAdCompleteListener: OnShowAdCompleteListener + activity : Activity , onShowAdCompleteListener : OnShowAdCompleteListener ) { val isAdsChecked = runBlocking { dataStore.ads.first() } - if (isShowingAd || !isAdsChecked) { + if (isShowingAd || ! isAdsChecked) { return } - if (!isAdAvailable()) { + if (! isAdAvailable()) { onShowAdCompleteListener.onShowAdComplete() loadAd(activity) return } - appOpenAd!!.fullScreenContentCallback = object : FullScreenContentCallback() { + appOpenAd !!.fullScreenContentCallback = object : FullScreenContentCallback() { override fun onAdDismissedFullScreenContent() { appOpenAd = null isShowingAd = false @@ -131,7 +131,7 @@ class AppCoreManager : MultiDexApplication(), Application.ActivityLifecycleCallb loadAd(activity) } - override fun onAdFailedToShowFullScreenContent(adError: AdError) { + override fun onAdFailedToShowFullScreenContent(adError : AdError) { appOpenAd = null isShowingAd = false onShowAdCompleteListener.onShowAdComplete() @@ -142,7 +142,7 @@ class AppCoreManager : MultiDexApplication(), Application.ActivityLifecycleCallb } } isShowingAd = true - appOpenAd!!.show(activity) + appOpenAd !!.show(activity) } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/datastore/DataStore.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/datastore/DataStore.kt index 24102f3..e0210e8 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/datastore/DataStore.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/datastore/DataStore.kt @@ -12,14 +12,14 @@ import kotlinx.coroutines.flow.map val Context.dataStore by preferencesDataStore("settings") -class DataStore(context: Context) { +class DataStore(context : Context) { private val dataStore = context.dataStore companion object { @Volatile - private var instance: DataStore? = null + private var instance : DataStore? = null - fun getInstance(context: Context): DataStore { + fun getInstance(context : Context) : DataStore { return instance ?: synchronized(this) { instance ?: DataStore(context).also { instance = it } } @@ -29,11 +29,11 @@ class DataStore(context: Context) { // Last used app notifications private val lastUsedKey = longPreferencesKey("last_used") - val lastUsed: Flow = dataStore.data.map { preferences -> + val lastUsed : Flow = dataStore.data.map { preferences -> preferences[lastUsedKey] ?: 0 } - suspend fun saveLastUsed(timestamp: Long) { + suspend fun saveLastUsed(timestamp : Long) { dataStore.edit { preferences -> preferences[lastUsedKey] = timestamp } @@ -42,11 +42,11 @@ class DataStore(context: Context) { // Startup private val startupKey = booleanPreferencesKey("value") - val startup: Flow = dataStore.data.map { preferences -> + val startup : Flow = dataStore.data.map { preferences -> preferences[startupKey] ?: true } - suspend fun saveStartup(isFirstTime: Boolean) { + suspend fun saveStartup(isFirstTime : Boolean) { dataStore.edit { preferences -> preferences[startupKey] = isFirstTime } @@ -55,33 +55,33 @@ class DataStore(context: Context) { // Display val themeModeState = mutableStateOf("follow_system") private val themeModeKey = stringPreferencesKey("theme_mode") - val themeMode: Flow = dataStore.data.map { preferences -> + val themeMode : Flow = dataStore.data.map { preferences -> preferences[themeModeKey] ?: "follow_system" } - suspend fun saveThemeMode(mode: String) { + suspend fun saveThemeMode(mode : String) { dataStore.edit { preferences -> preferences[themeModeKey] = mode } } private val amoledModeKey = booleanPreferencesKey("amoled_mode") - val amoledMode: Flow = dataStore.data.map { preferences -> + val amoledMode : Flow = dataStore.data.map { preferences -> preferences[amoledModeKey] ?: false } - suspend fun saveAmoledMode(isChecked: Boolean) { + suspend fun saveAmoledMode(isChecked : Boolean) { dataStore.edit { preferences -> preferences[amoledModeKey] = isChecked } } private val dynamicColorsKey = booleanPreferencesKey("dynamic_colors") - val dynamicColors: Flow = dataStore.data.map { preferences -> + val dynamicColors : Flow = dataStore.data.map { preferences -> preferences[dynamicColorsKey] ?: true } - suspend fun saveDynamicColors(isChecked: Boolean) { + suspend fun saveDynamicColors(isChecked : Boolean) { dataStore.edit { preferences -> preferences[dynamicColorsKey] = isChecked } @@ -89,11 +89,11 @@ class DataStore(context: Context) { private val languageKey = stringPreferencesKey("language") - fun getLanguage(): Flow = dataStore.data.map { preferences -> + fun getLanguage() : Flow = dataStore.data.map { preferences -> preferences[languageKey] ?: "en" } - suspend fun saveLanguage(language: String) { + suspend fun saveLanguage(language : String) { dataStore.edit { preferences -> preferences[languageKey] = language } @@ -101,143 +101,143 @@ class DataStore(context: Context) { // Cleaning private val genericFilterKey = booleanPreferencesKey("generic_filter") - val genericFilter: Flow = dataStore.data.map { preferences -> + val genericFilter : Flow = dataStore.data.map { preferences -> preferences[genericFilterKey] ?: false } - suspend fun saveGenericFilter(isChecked: Boolean) { + suspend fun saveGenericFilter(isChecked : Boolean) { dataStore.edit { preferences -> preferences[genericFilterKey] = isChecked } } private val deleteEmptyFoldersKey = booleanPreferencesKey("delete_empty_folders") - val deleteEmptyFolders: Flow = dataStore.data.map { preferences -> + val deleteEmptyFolders : Flow = dataStore.data.map { preferences -> preferences[deleteEmptyFoldersKey] ?: true } - suspend fun saveDeleteEmptyFolders(isChecked: Boolean) { + suspend fun saveDeleteEmptyFolders(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteEmptyFoldersKey] = isChecked } } private val deleteArchivesKey = booleanPreferencesKey("delete_archives") - val deleteArchives: Flow = dataStore.data.map { preferences -> + val deleteArchives : Flow = dataStore.data.map { preferences -> preferences[deleteArchivesKey] ?: false } - suspend fun saveDeleteArchives(isChecked: Boolean) { + suspend fun saveDeleteArchives(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteArchivesKey] = isChecked } } private val deleteInvalidMediaKey = booleanPreferencesKey("delete_invalid_media") - val deleteInvalidMedia: Flow = dataStore.data.map { preferences -> + val deleteInvalidMedia : Flow = dataStore.data.map { preferences -> preferences[deleteInvalidMediaKey] ?: false } - suspend fun saveDeleteInvalidMedia(isChecked: Boolean) { + suspend fun saveDeleteInvalidMedia(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteInvalidMediaKey] = isChecked } } private val deleteCorpseFilesKey = booleanPreferencesKey("delete_corpse_files") - val deleteCorpseFiles: Flow = dataStore.data.map { preferences -> + val deleteCorpseFiles : Flow = dataStore.data.map { preferences -> preferences[deleteCorpseFilesKey] ?: false } - suspend fun saveDeleteCorpseFiles(isChecked: Boolean) { + suspend fun saveDeleteCorpseFiles(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteCorpseFilesKey] = isChecked } } private val deleteApkFilesKey = booleanPreferencesKey("delete_apk_files") - val deleteApkFiles: Flow = dataStore.data.map { preferences -> + val deleteApkFiles : Flow = dataStore.data.map { preferences -> preferences[deleteApkFilesKey] ?: true } - suspend fun saveDeleteApkFiles(isChecked: Boolean) { + suspend fun saveDeleteApkFiles(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteApkFilesKey] = isChecked } } private val deleteAudioFilesKey = booleanPreferencesKey("delete_audio_files") - val deleteAudioFiles: Flow = dataStore.data.map { preferences -> + val deleteAudioFiles : Flow = dataStore.data.map { preferences -> preferences[deleteAudioFilesKey] ?: true } - suspend fun saveDeleteAudioFiles(isChecked: Boolean) { + suspend fun saveDeleteAudioFiles(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteAudioFilesKey] = isChecked } } private val deleteVideoFilesKey = booleanPreferencesKey("delete_video_files") - val deleteVideoFiles: Flow = dataStore.data.map { preferences -> + val deleteVideoFiles : Flow = dataStore.data.map { preferences -> preferences[deleteVideoFilesKey] ?: true } - suspend fun saveDeleteVideoFiles(isChecked: Boolean) { + suspend fun saveDeleteVideoFiles(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteVideoFilesKey] = isChecked } } private val deleteImageFilesKey = booleanPreferencesKey("delete_image_files") - val deleteImageFiles: Flow = dataStore.data.map { preferences -> + val deleteImageFiles : Flow = dataStore.data.map { preferences -> preferences[deleteImageFilesKey] ?: true } - suspend fun saveDeleteImageFiles(isChecked: Boolean) { + suspend fun saveDeleteImageFiles(isChecked : Boolean) { dataStore.edit { preferences -> preferences[deleteImageFilesKey] = isChecked } } private val doubleCheckerKey = booleanPreferencesKey("double_checker") - val doubleChecker: Flow = dataStore.data.map { preferences -> + val doubleChecker : Flow = dataStore.data.map { preferences -> preferences[doubleCheckerKey] ?: false } - suspend fun saveDoubleChecker(isChecked: Boolean) { + suspend fun saveDoubleChecker(isChecked : Boolean) { dataStore.edit { preferences -> preferences[doubleCheckerKey] = isChecked } } private val clipboardCleanKey = booleanPreferencesKey("clipboard_clean") - val clipboardClean: Flow = dataStore.data.map { preferences -> + val clipboardClean : Flow = dataStore.data.map { preferences -> preferences[clipboardCleanKey] ?: false } - suspend fun saveClipboardClean(isChecked: Boolean) { + suspend fun saveClipboardClean(isChecked : Boolean) { dataStore.edit { preferences -> preferences[clipboardCleanKey] = isChecked } } private val oneClickCleanKey = booleanPreferencesKey("one_click_clean") - val oneClickClean: Flow = dataStore.data.map { preferences -> + val oneClickClean : Flow = dataStore.data.map { preferences -> preferences[oneClickCleanKey] ?: false } - suspend fun saveOneClickClean(isChecked: Boolean) { + suspend fun saveOneClickClean(isChecked : Boolean) { dataStore.edit { preferences -> preferences[oneClickCleanKey] = isChecked } } private val dailyCleanerKey = booleanPreferencesKey("daily_clean") - val dailyCleaner: Flow = dataStore.data.map { preferences -> + val dailyCleaner : Flow = dataStore.data.map { preferences -> preferences[dailyCleanerKey] ?: false } - suspend fun saveDailyCleaner(isChecked: Boolean) { + suspend fun saveDailyCleaner(isChecked : Boolean) { dataStore.edit { preferences -> preferences[dailyCleanerKey] = isChecked } @@ -245,11 +245,11 @@ class DataStore(context: Context) { // Usage and Diagnostics private val usageAndDiagnosticsKey = booleanPreferencesKey("usage_and_diagnostics") - val usageAndDiagnostics: Flow = dataStore.data.map { preferences -> + val usageAndDiagnostics : Flow = dataStore.data.map { preferences -> preferences[usageAndDiagnosticsKey] ?: true } - suspend fun saveUsageAndDiagnostics(isChecked: Boolean) { + suspend fun saveUsageAndDiagnostics(isChecked : Boolean) { dataStore.edit { preferences -> preferences[usageAndDiagnosticsKey] = isChecked } @@ -257,11 +257,11 @@ class DataStore(context: Context) { // Ads private val adsKey = booleanPreferencesKey("ads") - val ads: Flow = dataStore.data.map { preferences -> + val ads : Flow = dataStore.data.map { preferences -> preferences[adsKey] ?: true } - suspend fun saveAds(isChecked: Boolean) { + suspend fun saveAds(isChecked : Boolean) { dataStore.edit { preferences -> preferences[adsKey] = isChecked } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/appmanager/ui/ApkInfo.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/appmanager/ui/ApkInfo.kt index 87d9c0f..42abeb7 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/appmanager/ui/ApkInfo.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/appmanager/ui/ApkInfo.kt @@ -1,7 +1,5 @@ package com.d4rk.cleaner.data.model.ui.appmanager.ui data class ApkInfo( - val id: Long, - val path: String, - val size: Long + val id : Long , val path : String , val size : Long ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/CompressionLevel.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/CompressionLevel.kt index 7dc973d..637bea2 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/CompressionLevel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/CompressionLevel.kt @@ -2,8 +2,6 @@ package com.d4rk.cleaner.data.model.ui.imageoptimizer import com.d4rk.cleaner.R -enum class CompressionLevel(val stringRes: Int, val defaultPercentage: Int) { - LOW(R.string.low, 25), - MEDIUM(R.string.medium, 50), - HIGH(R.string.high, 75) +enum class CompressionLevel(val stringRes : Int , val defaultPercentage : Int) { + LOW(R.string.low , 25) , MEDIUM(R.string.medium , 50) , HIGH(R.string.high , 75) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/ImageOptimizerState.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/ImageOptimizerState.kt index d40f22e..75e3bc6 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/ImageOptimizerState.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/imageoptimizer/ImageOptimizerState.kt @@ -3,13 +3,13 @@ package com.d4rk.cleaner.data.model.ui.imageoptimizer import android.net.Uri data class ImageOptimizerState( - val selectedImageUri: Uri? = null, - val compressedImageUri: Uri? = null, - val isLoading: Boolean = false, - val quickCompressValue: Int = 50, - val fileSizeKB: Int = 0, - val manualWidth: Int = 0, - val manualHeight: Int = 0, - val manualQuality: Int = 50, - val currentTab: Int = 0, + val selectedImageUri : Uri? = null , + val compressedImageUri : Uri? = null , + val isLoading : Boolean = false , + val quickCompressValue : Int = 50 , + val fileSizeKB : Int = 0 , + val manualWidth : Int = 0 , + val manualHeight : Int = 0 , + val manualQuality : Int = 50 , + val currentTab : Int = 0 , ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/InternalStorageInfo.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/InternalStorageInfo.kt index 8cc466a..81db487 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/InternalStorageInfo.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/InternalStorageInfo.kt @@ -1,7 +1,5 @@ package com.d4rk.cleaner.data.model.ui.memorymanager data class InternalStorageInfo( - val totalStorage: Long, - val freeStorage: Long, - val usedStorage: Long + val totalStorage : Long , val freeStorage : Long , val usedStorage : Long ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/RamInfo.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/RamInfo.kt index 99f77ba..e84564e 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/RamInfo.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/RamInfo.kt @@ -1,7 +1,5 @@ package com.d4rk.cleaner.data.model.ui.memorymanager data class RamInfo( - val totalRam: Long = 0, - val availableRam: Long = 0, - val usedRam: Long = 0 + val totalRam : Long = 0 , val availableRam : Long = 0 , val usedRam : Long = 0 ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/StorageInfo.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/StorageInfo.kt index a0db11a..6d5cc05 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/StorageInfo.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/memorymanager/StorageInfo.kt @@ -1,8 +1,8 @@ package com.d4rk.cleaner.data.model.ui.memorymanager data class StorageInfo( - val totalStorage: Long = 0, - val freeStorage: Long = 0, - val usedStorage: Long = 0, - val storageBreakdown: Map = emptyMap() + val totalStorage : Long = 0 , + val freeStorage : Long = 0 , + val usedStorage : Long = 0 , + val storageBreakdown : Map = emptyMap() ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/BottomNavigationScreen.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/BottomNavigationScreen.kt index d01bb74..26ce7cc 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/BottomNavigationScreen.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/BottomNavigationScreen.kt @@ -12,29 +12,23 @@ import com.d4rk.cleaner.R import com.d4rk.cleaner.constants.ui.bottombar.BottomBarRoutes sealed class BottomNavigationScreen( - val route: String, - val icon: ImageVector, - val selectedIcon: ImageVector, - val title: Int + val route : String , val icon : ImageVector , val selectedIcon : ImageVector , val title : Int ) { data object Home : BottomNavigationScreen( - BottomBarRoutes.HOME, - Icons.Outlined.Home, - Icons.Filled.Home, - R.string.home + BottomBarRoutes.HOME , Icons.Outlined.Home , Icons.Filled.Home , R.string.home ) data object AppManager : BottomNavigationScreen( - BottomBarRoutes.APP_MANAGER, - Icons.Sharp.AppRegistration, - Icons.Rounded.AppRegistration, + BottomBarRoutes.APP_MANAGER , + Icons.Sharp.AppRegistration , + Icons.Rounded.AppRegistration , R.string.app_manager ) data object MemoryManager : BottomNavigationScreen( - BottomBarRoutes.MEMORY_MANAGER, - Icons.Sharp.Storage, - Icons.Rounded.Storage, + BottomBarRoutes.MEMORY_MANAGER , + Icons.Sharp.Storage , + Icons.Rounded.Storage , R.string.memory_manager ) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/NavigationDrawerItem.kt b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/NavigationDrawerItem.kt index 0d946db..1e49e55 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/NavigationDrawerItem.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/data/model/ui/navigation/NavigationDrawerItem.kt @@ -3,5 +3,5 @@ package com.d4rk.cleaner.data.model.ui.navigation import androidx.compose.ui.graphics.vector.ImageVector data class NavigationDrawerItem( - val title: Int, val selectedIcon: ImageVector, val badgeCount: Int? = null + val title : Int , val selectedIcon : ImageVector , val badgeCount : Int? = null ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUpdateNotificationsManager.kt b/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUpdateNotificationsManager.kt index 535bdd5..4033dea 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUpdateNotificationsManager.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUpdateNotificationsManager.kt @@ -20,7 +20,7 @@ import com.google.android.play.core.install.model.UpdateAvailability * * @property context The application context used for notification management. */ -class AppUpdateNotificationsManager(private val context: Context) { +class AppUpdateNotificationsManager(private val context : Context) { private val updateChannelId = "update_channel" private val updateNotificationId = 0 @@ -32,7 +32,7 @@ class AppUpdateNotificationsManager(private val context: Context) { */ fun checkAndSendUpdateNotification() { val notificationManager = - context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val appUpdateInfoTask = AppUpdateManagerFactory.create(context).appUpdateInfo appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed( @@ -40,24 +40,24 @@ class AppUpdateNotificationsManager(private val context: Context) { ) ) { val updateChannel = NotificationChannel( - updateChannelId, - context.getString(R.string.update_notifications), + updateChannelId , + context.getString(R.string.update_notifications) , NotificationManager.IMPORTANCE_HIGH ) notificationManager.createNotificationChannel(updateChannel) - val updateBuilder = NotificationCompat.Builder(context, updateChannelId) - .setSmallIcon(R.drawable.ic_notification_update) - .setContentTitle(context.getString(R.string.notification_update_title)) - .setContentText(context.getString(R.string.summary_notification_update)) - .setAutoCancel(true).setContentIntent( - PendingIntent.getActivity( - context, 0, Intent( - Intent.ACTION_VIEW, - Uri.parse("market://details?id=${context.packageName}") - ), PendingIntent.FLAG_IMMUTABLE + val updateBuilder = NotificationCompat.Builder(context , updateChannelId) + .setSmallIcon(R.drawable.ic_notification_update) + .setContentTitle(context.getString(R.string.notification_update_title)) + .setContentText(context.getString(R.string.summary_notification_update)) + .setAutoCancel(true).setContentIntent( + PendingIntent.getActivity( + context , 0 , Intent( + Intent.ACTION_VIEW , + Uri.parse("market://details?id=${context.packageName}") + ) , PendingIntent.FLAG_IMMUTABLE + ) ) - ) - notificationManager.notify(updateNotificationId, updateBuilder.build()) + notificationManager.notify(updateNotificationId , updateBuilder.build()) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUsageNotificationsManager.kt b/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUsageNotificationsManager.kt index 2fd3c1f..26a4908 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUsageNotificationsManager.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/notifications/managers/AppUsageNotificationsManager.kt @@ -15,12 +15,12 @@ import java.util.concurrent.TimeUnit * * @property context The application context used for scheduling app usage checks. */ -class AppUsageNotificationsManager(private val context: Context) { +class AppUsageNotificationsManager(private val context : Context) { private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager private val notificationIntent = - Intent(context, AppUsageNotificationReceiver::class.java).let { intent -> - PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE) - } + Intent(context , AppUsageNotificationReceiver::class.java).let { intent -> + PendingIntent.getBroadcast(context , 0 , intent , PendingIntent.FLAG_IMMUTABLE) + } /** * Schedules a periodic check for app usage notifications. @@ -32,7 +32,7 @@ class AppUsageNotificationsManager(private val context: Context) { fun scheduleAppUsageCheck() { val triggerTime = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(3) alarmManager.setRepeating( - AlarmManager.RTC_WAKEUP, triggerTime, TimeUnit.DAYS.toMillis(3), notificationIntent + AlarmManager.RTC_WAKEUP , triggerTime , TimeUnit.DAYS.toMillis(3) , notificationIntent ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/notifications/receivers/AppUsageNotificationReceiver.kt b/app/src/main/kotlin/com/d4rk/cleaner/notifications/receivers/AppUsageNotificationReceiver.kt index 8d9e20d..d108fdd 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/notifications/receivers/AppUsageNotificationReceiver.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/notifications/receivers/AppUsageNotificationReceiver.kt @@ -8,7 +8,7 @@ import androidx.work.WorkManager import com.d4rk.cleaner.notifications.workers.AppUsageNotificationWorker class AppUsageNotificationReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent?) { + override fun onReceive(context : Context , intent : Intent?) { val workRequest = OneTimeWorkRequestBuilder().build() WorkManager.getInstance(context).enqueue(workRequest) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/notifications/workers/AppUsageNotificationWorker.kt b/app/src/main/kotlin/com/d4rk/cleaner/notifications/workers/AppUsageNotificationWorker.kt index 47bca6e..d879e7c 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/notifications/workers/AppUsageNotificationWorker.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/notifications/workers/AppUsageNotificationWorker.kt @@ -21,8 +21,8 @@ import kotlinx.coroutines.runBlocking * @property context The application context used for accessing system services and resources. * @property workerParams The parameters for this worker instance. */ -class AppUsageNotificationWorker(context: Context, workerParams: WorkerParameters) : - Worker(context, workerParams) { +class AppUsageNotificationWorker(context : Context , workerParams : WorkerParameters) : + Worker(context , workerParams) { private val dataStore = DataStore.getInstance(context) private val appUsageChannelId = "app_usage_channel" private val appUsageNotificationId = 0 @@ -36,26 +36,26 @@ class AppUsageNotificationWorker(context: Context, workerParams: WorkerParameter * * @return The result of the worker operation, indicating success or failure. */ - override fun doWork(): Result { + override fun doWork() : Result { val currentTimestamp = System.currentTimeMillis() val notificationThreshold = 3 * 24 * 60 * 60 * 1000 val lastUsedTimestamp = runBlocking { dataStore.lastUsed.first() } if (currentTimestamp - lastUsedTimestamp > notificationThreshold) { val notificationManager = - applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager val appUsageChannel = NotificationChannel( - appUsageChannelId, - applicationContext.getString(R.string.app_usage_notifications), + appUsageChannelId , + applicationContext.getString(R.string.app_usage_notifications) , NotificationManager.IMPORTANCE_HIGH ) notificationManager.createNotificationChannel(appUsageChannel) val notificationBuilder = - NotificationCompat.Builder(applicationContext, appUsageChannelId) - .setSmallIcon(R.drawable.ic_notification_important) - .setContentTitle(applicationContext.getString(R.string.notification_last_time_used_title)) - .setContentText(applicationContext.getString(R.string.summary_notification_last_time_used)) - .setAutoCancel(true) - notificationManager.notify(appUsageNotificationId, notificationBuilder.build()) + NotificationCompat.Builder(applicationContext , appUsageChannelId) + .setSmallIcon(R.drawable.ic_notification_important) + .setContentTitle(applicationContext.getString(R.string.notification_last_time_used_title)) + .setContentText(applicationContext.getString(R.string.summary_notification_last_time_used)) + .setAutoCancel(true) + notificationManager.notify(appUsageNotificationId , notificationBuilder.build()) } runBlocking { dataStore.saveLastUsed(currentTimestamp) } return Result.success() diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/appmanager/AppManagerViewModelFactory.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/appmanager/AppManagerViewModelFactory.kt index d968c5d..c4cd2d3 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/appmanager/AppManagerViewModelFactory.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/appmanager/AppManagerViewModelFactory.kt @@ -4,11 +4,11 @@ import android.app.Application import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -class AppManagerViewModelFactory(private val application: Application) : ViewModelProvider.Factory { - override fun create(modelClass: Class): T { +class AppManagerViewModelFactory(private val application : Application) : + ViewModelProvider.Factory { + override fun create(modelClass : Class) : T { if (modelClass.isAssignableFrom(AppManagerViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return AppManagerViewModel(application) as T + @Suppress("UNCHECKED_CAST") return AppManagerViewModel(application) as T } throw IllegalArgumentException("Unknown ViewModel class") } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/LanguageDialogComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/LanguageDialogComposable.kt index 6e02be7..e98caf2 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/LanguageDialogComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/LanguageDialogComposable.kt @@ -34,26 +34,26 @@ import kotlinx.coroutines.flow.firstOrNull @Composable fun LanguageDialog( - dataStore: DataStore , onDismiss: () -> Unit , onLanguageSelected: (String) -> Unit + dataStore : DataStore , onDismiss : () -> Unit , onLanguageSelected : (String) -> Unit ) { val selectedLanguage = remember { mutableStateOf("") } val languageEntries = stringArrayResource(R.array.preference_language_entries).toList() val languageValues = stringArrayResource(R.array.preference_language_values).toList() - AlertDialog(onDismissRequest = onDismiss, text = { + AlertDialog(onDismissRequest = onDismiss , text = { LanguageDialogContent( - selectedLanguage, dataStore, languageEntries, languageValues + selectedLanguage , dataStore , languageEntries , languageValues ) - }, icon = { - Icon(Icons.Outlined.Language, contentDescription = null) - }, confirmButton = { + } , icon = { + Icon(Icons.Outlined.Language , contentDescription = null) + } , confirmButton = { TextButton(onClick = { onLanguageSelected(selectedLanguage.value) onDismiss() }) { Text(stringResource(android.R.string.ok)) } - }, dismissButton = { + } , dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(android.R.string.cancel)) } @@ -62,10 +62,10 @@ fun LanguageDialog( @Composable fun LanguageDialogContent( - selectedLanguage: MutableState, - dataStore: DataStore, - languageEntries: List, - languageValues: List + selectedLanguage : MutableState , + dataStore : DataStore , + languageEntries : List , + languageValues : List ) { LaunchedEffect(Unit) { selectedLanguage.value = dataStore.getLanguage().firstOrNull() ?: "" @@ -75,24 +75,23 @@ fun LanguageDialogContent( Text(stringResource(id = R.string.dialog_language_subtitle)) Box( modifier = Modifier - .fillMaxWidth() - .weight(1f) + .fillMaxWidth() + .weight(1f) ) { LazyColumn { items(languageEntries.size) { index -> Row( - Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, + Modifier.fillMaxWidth() , + verticalAlignment = Alignment.CenterVertically , horizontalArrangement = Arrangement.Start ) { - RadioButton( - selected = selectedLanguage.value == languageValues[index], - onClick = { - selectedLanguage.value = languageValues[index] - }) + RadioButton(selected = selectedLanguage.value == languageValues[index] , + onClick = { + selectedLanguage.value = languageValues[index] + }) Text( - modifier = Modifier.padding(start = 8.dp), - text = languageEntries[index], + modifier = Modifier.padding(start = 8.dp) , + text = languageEntries[index] , style = MaterialTheme.typography.bodyMedium.merge() ) } @@ -100,7 +99,7 @@ fun LanguageDialogContent( } } Spacer(modifier = Modifier.height(24.dp)) - Icon(imageVector = Icons.Outlined.Info, contentDescription = null) + Icon(imageVector = Icons.Outlined.Info , contentDescription = null) Spacer(modifier = Modifier.height(12.dp)) Text(stringResource(id = R.string.dialog_info_language)) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RequireRestartDialog.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RequireRestartDialog.kt index 57a0492..2354b19 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RequireRestartDialog.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RequireRestartDialog.kt @@ -12,19 +12,19 @@ import com.d4rk.cleaner.R import com.google.android.material.dialog.MaterialAlertDialogBuilder class RequireRestartDialog : DialogFragment() { - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog { return MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.require_restart) - .setMessage(R.string.summary_require_restart) - .setPositiveButton(android.R.string.ok) { _, _ -> - activity?.recreate() - val nManager = - requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - nManager.cancelAll() - val pm: PackageManager = requireContext().packageManager - val intent = pm.getLaunchIntentForPackage(requireContext().packageName) - intent?.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK - requireContext().startActivity(intent) - Process.killProcess(Process.myPid()) - }.setNegativeButton(android.R.string.cancel, null).show() + .setMessage(R.string.summary_require_restart) + .setPositiveButton(android.R.string.ok) { _ , _ -> + activity?.recreate() + val nManager = + requireContext().getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + nManager.cancelAll() + val pm : PackageManager = requireContext().packageManager + val intent = pm.getLaunchIntentForPackage(requireContext().packageName) + intent?.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK + requireContext().startActivity(intent) + Process.killProcess(Process.myPid()) + }.setNegativeButton(android.R.string.cancel , null).show() } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RescanDialogComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RescanDialogComposable.kt index 2e20548..5cb516b 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RescanDialogComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/RescanDialogComposable.kt @@ -10,22 +10,19 @@ import com.d4rk.cleaner.R @Composable fun RescanAlertDialog( - onYes: () -> Unit, - onDismiss: () -> Unit + onYes : () -> Unit , onDismiss : () -> Unit ) { - AlertDialog( - onDismissRequest = onDismiss, - title = { Text(stringResource(id = R.string.rescan_title)) }, - text = { Text(stringResource(id = R.string.rescan_message)) }, - confirmButton = { - TextButton(onClick = onYes) { - Text(stringResource(android.R.string.ok)) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(stringResource(android.R.string.cancel)) - } - } - ) + AlertDialog(onDismissRequest = onDismiss , + title = { Text(stringResource(id = R.string.rescan_title)) } , + text = { Text(stringResource(id = R.string.rescan_message)) } , + confirmButton = { + TextButton(onClick = onYes) { + Text(stringResource(android.R.string.ok)) + } + } , + dismissButton = { + TextButton(onClick = onDismiss) { + Text(stringResource(android.R.string.cancel)) + } + }) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/VersionInfoDialogComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/VersionInfoDialogComposable.kt index f56b69b..c3ad61e 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/VersionInfoDialogComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/dialogs/VersionInfoDialogComposable.kt @@ -22,11 +22,11 @@ import com.d4rk.cleaner.R import com.d4rk.cleaner.utils.cleaning.toBitmapDrawable @Composable -fun VersionInfoDialog(onDismiss: () -> Unit) { +fun VersionInfoDialog(onDismiss : () -> Unit) { AlertDialog( - onDismissRequest = onDismiss, - text = { VersionInfoContent() }, - confirmButton = {}, + onDismissRequest = onDismiss , + text = { VersionInfoContent() } , + confirmButton = {} , ) } @@ -35,36 +35,31 @@ fun VersionInfoContent() { val context = LocalContext.current val appName = context.getString(R.string.app_full_name) val versionName = BuildConfig.VERSION_NAME - val versionString = - stringResource(R.string.version, versionName) + val versionString = stringResource(R.string.version , versionName) val copyright = context.getString(R.string.copyright) val appIcon = context.packageManager.getApplicationIcon(context.packageName) val bitmapDrawable = appIcon.toBitmapDrawable() Row( - modifier = Modifier - .fillMaxWidth() + modifier = Modifier.fillMaxWidth() ) { Image( - bitmap = bitmapDrawable.bitmap.asImageBitmap(), - contentDescription = null, + bitmap = bitmapDrawable.bitmap.asImageBitmap() , + contentDescription = null , modifier = Modifier.size(48.dp) ) Spacer(modifier = Modifier.width(16.dp)) Column { Text( - text = appName, - style = MaterialTheme.typography.titleLarge + text = appName , style = MaterialTheme.typography.titleLarge ) Text( - text = versionString, - style = MaterialTheme.typography.bodyMedium + text = versionString , style = MaterialTheme.typography.bodyMedium ) Spacer(modifier = Modifier.height(16.dp)) Text( - text = copyright, - style = MaterialTheme.typography.bodyMedium + text = copyright , style = MaterialTheme.typography.bodyMedium ) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpActivity.kt index 40592c5..91620cb 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpActivity.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.Modifier import com.d4rk.cleaner.ui.settings.display.theme.style.AppTheme class HelpActivity : AppCompatActivity() { - private val viewModel: HelpViewModel by viewModels() + private val viewModel : HelpViewModel by viewModels() override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() @@ -21,7 +21,7 @@ class HelpActivity : AppCompatActivity() { Surface( modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { - HelpComposable(this@HelpActivity, viewModel) + HelpComposable(this@HelpActivity , viewModel) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpComposable.kt index c5e8ce1..1518202 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpComposable.kt @@ -53,7 +53,7 @@ import com.google.android.gms.oss.licenses.OssLicensesMenuActivity @OptIn(ExperimentalMaterial3Api::class) @Composable -fun HelpComposable(activity : HelpActivity, viewModel: HelpViewModel) { +fun HelpComposable(activity : HelpActivity , viewModel : HelpViewModel) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) var showMenu by remember { mutableStateOf(false) } val context = LocalContext.current @@ -79,41 +79,41 @@ fun HelpComposable(activity : HelpActivity, viewModel: HelpViewModel) { } DropdownMenu(expanded = showMenu , onDismissRequest = { showMenu = false }) { DropdownMenuItem(text = { Text(stringResource(R.string.view_in_google_play_store)) } , - onClick = { - IntentUtils.openUrl( - context , - "https://play.google.com/store/apps/details?id=${activity.packageName}" - ) - }) + onClick = { + IntentUtils.openUrl( + context , + "https://play.google.com/store/apps/details?id=${activity.packageName}" + ) + }) DropdownMenuItem(text = { Text(stringResource(R.string.version_info)) } , - onClick = { showDialog.value = true }) + onClick = { showDialog.value = true }) DropdownMenuItem(text = { Text(stringResource(R.string.beta_program)) } , - onClick = { - IntentUtils.openUrl( - context , - "https://play.google.com/apps/testing/${activity.packageName}" - ) - }) + onClick = { + IntentUtils.openUrl( + context , + "https://play.google.com/apps/testing/${activity.packageName}" + ) + }) DropdownMenuItem(text = { Text(stringResource(R.string.terms_of_service)) } , - onClick = { - IntentUtils.openUrl( - context , - "https://sites.google.com/view/d4rk7355608/more/apps/terms-of-service" - ) - }) + onClick = { + IntentUtils.openUrl( + context , + "https://sites.google.com/view/d4rk7355608/more/apps/terms-of-service" + ) + }) DropdownMenuItem(text = { Text(stringResource(R.string.privacy_policy)) } , - onClick = { - IntentUtils.openUrl( - context , - "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy" - ) - }) + onClick = { + IntentUtils.openUrl( + context , + "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy" + ) + }) DropdownMenuItem(text = { Text(stringResource(com.google.android.gms.oss.licenses.R.string.oss_license_title)) } , - onClick = { - IntentUtils.openActivity( - context , OssLicensesMenuActivity::class.java - ) - }) + onClick = { + IntentUtils.openActivity( + context , OssLicensesMenuActivity::class.java + ) + }) } if (showDialog.value) { VersionInfoDialog(onDismiss = { showDialog.value = false }) @@ -122,25 +122,25 @@ fun HelpComposable(activity : HelpActivity, viewModel: HelpViewModel) { }) { paddingValues -> Box( modifier = Modifier - .padding(start = 16.dp , end = 16.dp) - .fillMaxSize() - .safeDrawingPadding() + .padding(start = 16.dp , end = 16.dp) + .fillMaxSize() + .safeDrawingPadding() ) { ConstraintLayout(modifier = Modifier.padding(paddingValues)) { val (faqTitle , faqCard) = createRefs() Text(text = stringResource(R.string.faq) , - modifier = Modifier - .padding(bottom = 24.dp) - .constrainAs(faqTitle) { - top.linkTo(parent.top) - start.linkTo(parent.start) - }) + modifier = Modifier + .padding(bottom = 24.dp) + .constrainAs(faqTitle) { + top.linkTo(parent.top) + start.linkTo(parent.start) + }) Card(modifier = Modifier - .fillMaxWidth() - .constrainAs(faqCard) { - top.linkTo(faqTitle.bottom) - bottom.linkTo(parent.bottom) - }) { + .fillMaxWidth() + .constrainAs(faqCard) { + top.linkTo(faqTitle.bottom) + bottom.linkTo(parent.bottom) + }) { FAQComposable() } } @@ -148,18 +148,18 @@ fun HelpComposable(activity : HelpActivity, viewModel: HelpViewModel) { text = { Text(stringResource(id = R.string.feedback)) } , onClick = { viewModel.reviewInfo.value?.let { safeReviewInfo -> - viewModel.launchReviewFlow(activity, safeReviewInfo) + viewModel.launchReviewFlow(activity , safeReviewInfo) } - }, + } , icon = { Icon( Icons.Default.MailOutline , contentDescription = null ) } , modifier = Modifier - .bounceClick() - .padding(bottom = 16.dp) - .align(Alignment.BottomEnd) , + .bounceClick() + .padding(bottom = 16.dp) + .align(Alignment.BottomEnd) , ) } } @@ -229,19 +229,19 @@ fun FAQComposable() { fun QuestionComposable(title : String , summary : String) { Row( modifier = Modifier - .fillMaxWidth() - .padding(16.dp) , + .fillMaxWidth() + .padding(16.dp) , verticalAlignment = Alignment.CenterVertically ) { Icon( Icons.Outlined.QuestionAnswer , contentDescription = null , modifier = Modifier - .size(48.dp) - .background( - color = MaterialTheme.colorScheme.primaryContainer , shape = CircleShape - ) - .padding(8.dp) + .size(48.dp) + .background( + color = MaterialTheme.colorScheme.primaryContainer , shape = CircleShape + ) + .padding(8.dp) ) Spacer(modifier = Modifier.width(16.dp)) Column { diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpViewModel.kt index d99844b..1782a1b 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/help/HelpViewModel.kt @@ -1,7 +1,9 @@ package com.d4rk.cleaner.ui.help import android.app.Application -import androidx.compose.runtime.* +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.google.android.play.core.review.ReviewInfo @@ -9,10 +11,10 @@ import com.google.android.play.core.review.ReviewManagerFactory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -class HelpViewModel(application: Application) : AndroidViewModel(application) { +class HelpViewModel(application : Application) : AndroidViewModel(application) { - private var _reviewInfo: MutableState = mutableStateOf(null) - val reviewInfo: State = _reviewInfo + private var _reviewInfo : MutableState = mutableStateOf(null) + val reviewInfo : State = _reviewInfo fun requestReviewFlow() { viewModelScope.launch(Dispatchers.IO) { @@ -21,15 +23,16 @@ class HelpViewModel(application: Application) : AndroidViewModel(application) { request.addOnCompleteListener { task -> if (task.isSuccessful) { _reviewInfo.value = task.result - } else { + } + else { task.exception?.printStackTrace() } } } } - fun launchReviewFlow(activity: HelpActivity, reviewInfo: ReviewInfo) { + fun launchReviewFlow(activity : HelpActivity , reviewInfo : ReviewInfo) { val reviewManager = ReviewManagerFactory.create(activity) - reviewManager.launchReviewFlow(activity, reviewInfo) + reviewManager.launchReviewFlow(activity , reviewInfo) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeComposable.kt index 30bc28d..9dfb3f4 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeComposable.kt @@ -71,17 +71,17 @@ import coil.memory.MemoryCache import coil.request.ImageRequest import com.d4rk.cleaner.R import com.d4rk.cleaner.ui.dialogs.RescanAlertDialog -import com.d4rk.cleaner.utils.compose.components.CircularDeterminateIndicator -import com.d4rk.cleaner.utils.compose.bounceClick import com.d4rk.cleaner.utils.cleaning.getFileIcon import com.d4rk.cleaner.utils.cleaning.getVideoThumbnail +import com.d4rk.cleaner.utils.compose.bounceClick +import com.d4rk.cleaner.utils.compose.components.CircularDeterminateIndicator import com.google.common.io.Files.getFileExtension import java.io.File @Composable fun HomeComposable() { val context = LocalContext.current - val viewModel: HomeViewModel = viewModel() + val viewModel : HomeViewModel = viewModel() val progress by viewModel.progress.observeAsState(0.3f) val storageUsed by viewModel.storageUsed.observeAsState("0") val storageTotal by viewModel.storageTotal.observeAsState("0") @@ -89,32 +89,22 @@ fun HomeComposable() { val isAnalyzing by viewModel.isAnalyzing.observeAsState(false) val selectedFileCount by viewModel.selectedFileCount.collectAsState() - val imageLoader = ImageLoader.Builder(context) - .memoryCache { - MemoryCache.Builder(context) - .maxSizePercent(0.24) - .build() - } - .diskCache { - DiskCache.Builder() - .directory(context.cacheDir.resolve("image_cache")) - .maxSizePercent(0.02) - .build() - } - .build() + val imageLoader = ImageLoader.Builder(context).memoryCache { + MemoryCache.Builder(context).maxSizePercent(0.24).build() + }.diskCache { + DiskCache.Builder().directory(context.cacheDir.resolve("image_cache")) + .maxSizePercent(0.02).build() + }.build() val launchScanningKey = remember { mutableStateOf(false) } if (viewModel.showRescanDialog.value) { - RescanAlertDialog( - onYes = { - viewModel.rescan( - context as Activity - ) - viewModel.showRescanDialog.value = false - }, - onDismiss = { viewModel.showRescanDialog.value = false } - ) + RescanAlertDialog(onYes = { + viewModel.rescan( + context as Activity + ) + viewModel.showRescanDialog.value = false + } , onDismiss = { viewModel.showRescanDialog.value = false }) } Column( @@ -122,110 +112,117 @@ fun HomeComposable() { ) { Box( modifier = Modifier - .weight(4f) - .fillMaxWidth() + .weight(4f) + .fillMaxWidth() ) { - if (!showCleaningComposable) { + if (! showCleaningComposable) { CircularDeterminateIndicator( - progress = progress, - storageUsed = storageUsed, - storageTotal = storageTotal, + progress = progress , + storageUsed = storageUsed , + storageTotal = storageTotal , modifier = Modifier - .align(Alignment.TopCenter) - .offset(y = 98.dp) + .align(Alignment.TopCenter) + .offset(y = 98.dp) ) Image( - painter = painterResource(R.drawable.ic_clean), - contentDescription = null, + painter = painterResource(R.drawable.ic_clean) , + contentDescription = null , modifier = Modifier - .align(Alignment.BottomCenter) - .padding(24.dp) - .size(128.dp, 66.dp) + .align(Alignment.BottomCenter) + .padding(24.dp) + .size(128.dp , 66.dp) ) - } else { - AnalyzeComposable(launchScanningKey, imageLoader) + } + else { + AnalyzeComposable(launchScanningKey , imageLoader) } } Row( modifier = Modifier - .fillMaxWidth() - .height(102.dp) - .padding(bottom = 16.dp), + .fillMaxWidth() + .height(102.dp) + .padding(bottom = 16.dp) , horizontalArrangement = Arrangement.SpaceEvenly ) { AnimatedVisibility( - visible = showCleaningComposable, + visible = showCleaningComposable , enter = fadeIn(animationSpec = tween(durationMillis = 400)) + expandHorizontally( - animationSpec = tween(durationMillis = 400), expandFrom = Alignment.Start - ), + animationSpec = tween(durationMillis = 400) , expandFrom = Alignment.Start + ) , exit = fadeOut(animationSpec = tween(durationMillis = 400)) + shrinkHorizontally( - animationSpec = tween(durationMillis = 400), shrinkTowards = Alignment.Start - ), + animationSpec = tween(durationMillis = 400) , shrinkTowards = Alignment.Start + ) , modifier = Modifier.weight(1f) ) { - val enabled = !isAnalyzing && selectedFileCount > 0 + val enabled = ! isAnalyzing && selectedFileCount > 0 val animateStateButtonColor = animateColorAsState( - targetValue = if (enabled) MaterialTheme.colorScheme.secondaryContainer else Color.LightGray, - animationSpec = tween(400, 0, LinearEasing), + targetValue = if (enabled) MaterialTheme.colorScheme.secondaryContainer else Color.LightGray , + animationSpec = tween(400 , 0 , LinearEasing) , label = "" ) FilledTonalButton( modifier = Modifier - .weight(1f) - .fillMaxHeight() - .animateContentSize() - .padding(start = 16.dp, end = 8.dp) - .bounceClick(), + .weight(1f) + .fillMaxHeight() + .animateContentSize() + .padding(start = 16.dp , end = 8.dp) + .bounceClick() , onClick = { viewModel.clean(activity = context as Activity) - }, - shape = MaterialTheme.shapes.medium, - enabled = enabled, + } , + shape = MaterialTheme.shapes.medium , + enabled = enabled , colors = ButtonDefaults.filledTonalButtonColors( - containerColor = animateStateButtonColor.value, - ), + containerColor = animateStateButtonColor.value , + ) , ) { Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally , + verticalArrangement = Arrangement.Center , modifier = Modifier - .fillMaxSize() - .padding(ButtonDefaults.ContentPadding) + .fillMaxSize() + .padding(ButtonDefaults.ContentPadding) ) { Icon( - painterResource(R.drawable.ic_broom), - contentDescription = null, + painterResource(R.drawable.ic_broom) , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) - Text(text = stringResource(R.string.clean), style = MaterialTheme.typography.bodyMedium) + Text( + text = stringResource(R.string.clean) , + style = MaterialTheme.typography.bodyMedium + ) } } } FilledTonalButton( modifier = Modifier - .weight(1f) - .fillMaxHeight() - .animateContentSize() - .padding(start = if (showCleaningComposable) 8.dp else 16.dp, end = 16.dp) - .bounceClick(), onClick = { + .weight(1f) + .fillMaxHeight() + .animateContentSize() + .padding(start = if (showCleaningComposable) 8.dp else 16.dp , end = 16.dp) + .bounceClick() , onClick = { viewModel.analyze(activity = context as Activity) - }, shape = MaterialTheme.shapes.medium + } , shape = MaterialTheme.shapes.medium ) { Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally , + verticalArrangement = Arrangement.Center , modifier = Modifier - .fillMaxSize() - .padding(ButtonDefaults.ContentPadding) + .fillMaxSize() + .padding(ButtonDefaults.ContentPadding) ) { Icon( - painterResource(R.drawable.ic_search), - contentDescription = null, + painterResource(R.drawable.ic_search) , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) - Text(text = stringResource(R.string.analyze), style = MaterialTheme.typography.bodyMedium) + Text( + text = stringResource(R.string.analyze) , + style = MaterialTheme.typography.bodyMedium + ) } } } @@ -241,8 +238,8 @@ fun HomeComposable() { * @param viewModel The HomeViewModel instance used to interact with the data and business logic. */ @Composable -fun AnalyzeComposable(launchScanningKey: MutableState, imageLoader: ImageLoader) { - val viewModel: HomeViewModel = viewModel() +fun AnalyzeComposable(launchScanningKey : MutableState , imageLoader : ImageLoader) { + val viewModel : HomeViewModel = viewModel() val files by viewModel.scannedFiles.asFlow().collectAsState(initial = listOf()) val isAnalyzing by viewModel.isAnalyzing.observeAsState(false) val allFilesSelected by viewModel.allFilesSelected @@ -259,64 +256,67 @@ fun AnalyzeComposable(launchScanningKey: MutableState, imageLoader: Ima Column( modifier = Modifier - .animateContentSize() - .fillMaxWidth() - .padding(16.dp), + .animateContentSize() + .fillMaxWidth() + .padding(16.dp) , horizontalAlignment = Alignment.End ) { OutlinedCard( modifier = Modifier - .weight(1f) - .fillMaxWidth(), + .weight(1f) + .fillMaxWidth() , ) { if (isAnalyzing && files.isEmpty()) { - Box (modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Box(modifier = Modifier.fillMaxSize() , contentAlignment = Alignment.Center) { CircularProgressIndicator() } - } else { + } + else { LazyVerticalGrid( - columns = GridCells.Fixed(3), - verticalArrangement = Arrangement.spacedBy(8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - modifier = Modifier.padding(8.dp), + columns = GridCells.Fixed(3) , + verticalArrangement = Arrangement.spacedBy(8.dp) , + horizontalArrangement = Arrangement.spacedBy(8.dp) , + modifier = Modifier.padding(8.dp) , ) { - items(files, key = { file -> file.absolutePath }) { file -> - FileCard(file = file, viewModel = viewModel, imageLoader = imageLoader) + items(files , key = { file -> file.absolutePath }) { file -> + FileCard(file = file , viewModel = viewModel , imageLoader = imageLoader) } } } } Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth() , + verticalAlignment = Alignment.CenterVertically , + horizontalArrangement = Arrangement.SpaceBetween , ) { val statusText = if (selectedFileCount > 0) { - stringResource(id = R.string.status_selected_files, selectedFileCount) - } else { + stringResource(id = R.string.status_selected_files , selectedFileCount) + } + else { stringResource(id = R.string.status_no_files_selected) } val statusColor by animateColorAsState( targetValue = if (selectedFileCount > 0) { MaterialTheme.colorScheme.primary - } else { + } + else { MaterialTheme.colorScheme.secondary - }, animationSpec = tween(), label = "" + } , animationSpec = tween() , label = "" ) Text( - text = statusText, color = statusColor, modifier = Modifier.animateContentSize() + text = statusText , color = statusColor , modifier = Modifier.animateContentSize() ) SelectAllComposable( - checked = allFilesSelected, - onCheckedChange = { viewModel.selectAllFiles(it) }, + checked = allFilesSelected , + onCheckedChange = { viewModel.selectAllFiles(it) } , ) } } } @Composable -fun FileCard(file: File, viewModel: HomeViewModel, imageLoader: ImageLoader) { +fun FileCard(file : File , viewModel : HomeViewModel , imageLoader : ImageLoader) { val context = LocalContext.current val fileExtension = getFileExtension(file.name) @@ -328,9 +328,9 @@ fun FileCard(file: File, viewModel: HomeViewModel, imageLoader: ImageLoader) { Card( modifier = Modifier - .fillMaxWidth() - .aspectRatio(1f) - .bounceClick(), + .fillMaxWidth() + .aspectRatio(1f) + .bounceClick() , elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) ) { Box(modifier = Modifier.fillMaxSize()) { @@ -338,68 +338,66 @@ fun FileCard(file: File, viewModel: HomeViewModel, imageLoader: ImageLoader) { in context.resources.getStringArray(R.array.image_extensions).toList() -> { AsyncImage( model = remember(file) { - ImageRequest.Builder(context) - .data(file) - .size(64) - .crossfade(true) - .build() - }, - imageLoader = imageLoader, - contentDescription = file.name, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize(), + ImageRequest.Builder(context).data(file).size(64).crossfade(true) + .build() + } , + imageLoader = imageLoader , + contentDescription = file.name , + contentScale = ContentScale.Crop , + modifier = Modifier.fillMaxSize() , ) } in context.resources.getStringArray(R.array.video_extensions).toList() -> { if (thumbnail != null) { Image( - bitmap = thumbnail!!.asImageBitmap(), - contentDescription = file.name, - contentScale = ContentScale.Crop, + bitmap = thumbnail !!.asImageBitmap() , + contentDescription = file.name , + contentScale = ContentScale.Crop , modifier = Modifier.fillMaxSize() ) - } else { + } + else { Icon( - painter = painterResource(R.drawable.ic_video_file), - contentDescription = null, + painter = painterResource(R.drawable.ic_video_file) , + contentDescription = null , modifier = Modifier - .size(24.dp) - .align(Alignment.Center) + .size(24.dp) + .align(Alignment.Center) ) } } else -> { Icon( - painter = painterResource(getFileIcon(fileExtension, context)), - contentDescription = null, + painter = painterResource(getFileIcon(fileExtension , context)) , + contentDescription = null , modifier = Modifier - .size(24.dp) - .align(Alignment.Center) + .size(24.dp) + .align(Alignment.Center) ) } } Checkbox( - checked = viewModel.fileSelectionStates[file] ?: false, + checked = viewModel.fileSelectionStates[file] ?: false , onCheckedChange = { isChecked -> - viewModel.onFileSelectionChange(file, isChecked) - }, + viewModel.onFileSelectionChange(file , isChecked) + } , modifier = Modifier.align(Alignment.TopEnd) ) Text( - text = file.name, - maxLines = 1, - overflow = TextOverflow.Ellipsis, + text = file.name , + maxLines = 1 , + overflow = TextOverflow.Ellipsis , modifier = Modifier - .fillMaxWidth() - .background( - color = Color.Black.copy(alpha = 0.4f) - ) - .padding(8.dp) - .align(Alignment.BottomCenter) + .fillMaxWidth() + .background( + color = Color.Black.copy(alpha = 0.4f) + ) + .padding(8.dp) + .align(Alignment.BottomCenter) ) } } @@ -416,34 +414,34 @@ fun FileCard(file: File, viewModel: HomeViewModel, imageLoader: ImageLoader) { */ @Composable fun SelectAllComposable( - checked: Boolean, onCheckedChange: (Boolean) -> Unit + checked : Boolean , onCheckedChange : (Boolean) -> Unit ) { Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize(), - verticalAlignment = Alignment.CenterVertically, + .fillMaxWidth() + .animateContentSize() , + verticalAlignment = Alignment.CenterVertically , horizontalArrangement = Arrangement.End ) { val interactionSource = remember { MutableInteractionSource() } FilterChip( - modifier = Modifier.bounceClick(), - selected = checked, + modifier = Modifier.bounceClick() , + selected = checked , onClick = { - onCheckedChange(!checked) - }, - label = { Text(stringResource(id = R.string.select_all)) }, + onCheckedChange(! checked) + } , + label = { Text(stringResource(id = R.string.select_all)) } , leadingIcon = { - AnimatedContent(targetState = checked, label = "") { targetChecked -> + AnimatedContent(targetState = checked , label = "") { targetChecked -> if (targetChecked) { Icon( - imageVector = Icons.Filled.Check, - contentDescription = null, + imageVector = Icons.Filled.Check , + contentDescription = null , ) } } - }, - interactionSource = interactionSource, + } , + interactionSource = interactionSource , ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt index 9d2493f..0498950 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/home/HomeViewModel.kt @@ -11,8 +11,8 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import com.d4rk.cleaner.data.datastore.DataStore -import com.d4rk.cleaner.utils.cleaning.FileScanner import com.d4rk.cleaner.utils.PermissionsUtils +import com.d4rk.cleaner.utils.cleaning.FileScanner import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -23,26 +23,26 @@ import java.io.File import java.util.UUID import kotlin.math.roundToInt -class HomeViewModel(application: Application) : AndroidViewModel(application) { +class HomeViewModel(application : Application) : AndroidViewModel(application) { val progress = MutableLiveData(0f) val storageUsed = MutableLiveData() val storageTotal = MutableLiveData() - var fileScanner: FileScanner + var fileScanner : FileScanner val scannedFiles = MutableLiveData>() val allFilesSelected = mutableStateOf(false) - val fileSelectionStates = mutableStateMapOf() - private val dataStoreInstance: DataStore = DataStore(application) + val fileSelectionStates = mutableStateMapOf() + private val dataStoreInstance : DataStore = DataStore(application) val showCleaningComposable = MutableLiveData(false) val isAnalyzing = MutableLiveData(false) var showRescanDialog = mutableStateOf(false) private var hasScanned = mutableStateOf(false) private var isUserConfirmedRescan = mutableStateOf(false) val _selectedFileCount = MutableStateFlow(0) - val selectedFileCount: StateFlow = _selectedFileCount.asStateFlow() + val selectedFileCount : StateFlow = _selectedFileCount.asStateFlow() init { updateStorageInfo() - fileScanner = FileScanner(dataStoreInstance, application.resources) + fileScanner = FileScanner(dataStoreInstance , application.resources) } /** @@ -63,15 +63,15 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { private fun updateStorageInfo() { viewModelScope.launch { val storageManager = - getApplication().getSystemService(Context.STORAGE_SERVICE) as StorageManager + getApplication().getSystemService(Context.STORAGE_SERVICE) as StorageManager val storageStatsManager = - getApplication().getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager + getApplication().getSystemService(Context.STORAGE_STATS_SERVICE) as StorageStatsManager val storageVolume = storageManager.primaryStorageVolume - val totalSize: Long - val usedSize: Long + val totalSize : Long + val usedSize : Long val uuidStr = storageVolume.uuid - val uuid: UUID = - if (uuidStr == null) StorageManager.UUID_DEFAULT else UUID.fromString(uuidStr) + val uuid : UUID = + if (uuidStr == null) StorageManager.UUID_DEFAULT else UUID.fromString(uuidStr) totalSize = storageStatsManager.getTotalBytes(uuid) usedSize = totalSize - storageStatsManager.getFreeBytes(uuid) storageUsed.postValue((usedSize / (1024.0 * 1024.0 * 1024.0)).roundToInt().toString()) @@ -80,7 +80,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { } } - fun onFileSelectionChange(file: File, isChecked: Boolean) { + fun onFileSelectionChange(file : File , isChecked : Boolean) { fileSelectionStates[file] = isChecked _selectedFileCount.value = fileSelectionStates.count { it.value } allFilesSelected.value = fileSelectionStates.all { it.value } @@ -98,7 +98,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { * selectAllFiles(true) // Selects all files * selectAllFiles(false) // Deselects all files */ - fun selectAllFiles(selectAll: Boolean) { + fun selectAllFiles(selectAll : Boolean) { viewModelScope.launch { withContext(Dispatchers.IO) { scannedFiles.value?.forEach { file -> @@ -117,13 +117,13 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { * * @param activity The Activity instance required to request permissions. */ - fun analyze(activity: Activity) { - if (!PermissionsUtils.hasStoragePermissions(getApplication())) { + fun analyze(activity : Activity) { + if (! PermissionsUtils.hasStoragePermissions(getApplication())) { PermissionsUtils.requestStoragePermissions(activity) return } - if (hasScanned.value && !isUserConfirmedRescan.value) { + if (hasScanned.value && ! isUserConfirmedRescan.value) { showRescanDialog.value = true } @@ -145,7 +145,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { } } - fun rescan(activity: Activity) { + fun rescan(activity : Activity) { showRescanDialog.value = false scannedFiles.value = emptyList() analyze(activity) @@ -156,8 +156,8 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { * * @param activity The Activity instance required to request permissions. */ - fun clean(activity: Activity) { - if (!PermissionsUtils.hasStoragePermissions(getApplication())) { + fun clean(activity : Activity) { + if (! PermissionsUtils.hasStoragePermissions(getApplication())) { PermissionsUtils.requestStoragePermissions(activity) return } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerActivity.kt index 9c345ba..0f70313 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerActivity.kt @@ -15,13 +15,13 @@ import com.d4rk.cleaner.ui.settings.display.theme.style.AppTheme import kotlinx.coroutines.launch class ImageOptimizerActivity : AppCompatActivity() { - private val viewModel: ImageOptimizerViewModel by viewModels() + private val viewModel : ImageOptimizerViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { + override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() val selectedImageUriString = intent.getStringExtra("selectedImageUri") - if (!selectedImageUriString.isNullOrEmpty()) { + if (! selectedImageUriString.isNullOrEmpty()) { lifecycleScope.launch { viewModel.onImageSelected(Uri.parse(selectedImageUriString)) } @@ -30,9 +30,9 @@ class ImageOptimizerActivity : AppCompatActivity() { setContent { AppTheme { Surface( - modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background + modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { - ImageOptimizerComposable(this@ImageOptimizerActivity, viewModel) + ImageOptimizerComposable(this@ImageOptimizerActivity , viewModel) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerComposable.kt index a88663e..aeec841 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerComposable.kt @@ -47,127 +47,113 @@ import com.d4rk.cleaner.ui.imageoptimizer.imageoptimizer.tabs.ManualModeScreen import com.d4rk.cleaner.ui.imageoptimizer.imageoptimizer.tabs.QuickCompressScreen import kotlinx.coroutines.launch -@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) +@OptIn(ExperimentalMaterial3Api::class , ExperimentalFoundationApi::class) @Composable -fun ImageOptimizerComposable(activity: ImageOptimizerActivity, viewModel: ImageOptimizerViewModel) { +fun ImageOptimizerComposable( + activity : ImageOptimizerActivity , + viewModel : ImageOptimizerViewModel +) { val context = LocalContext.current val dataStore = DataStore.getInstance(context) val coroutineScope = rememberCoroutineScope() val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) val adsState = dataStore.ads.collectAsState(initial = true) val tabs = listOf( - stringResource(R.string.quick_compress), - stringResource(R.string.file_size), - stringResource(R.string.manual), + stringResource(R.string.quick_compress) , + stringResource(R.string.file_size) , + stringResource(R.string.manual) , ) val pagerState = rememberPagerState(pageCount = { tabs.size }) - Scaffold( - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - LargeTopAppBar( - title = { Text(stringResource(R.string.image_optimizer)) }, - navigationIcon = { - IconButton(onClick = { - activity.finish() - }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) - } - }, - scrollBehavior = scrollBehavior - ) - } - ) { paddingValues -> + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { + LargeTopAppBar(title = { Text(stringResource(R.string.image_optimizer)) } , + navigationIcon = { + IconButton(onClick = { + activity.finish() + }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack , + contentDescription = null + ) + } + } , + scrollBehavior = scrollBehavior + ) + }) { paddingValues -> ConstraintLayout( modifier = Modifier - .fillMaxSize() - .padding(paddingValues) + .fillMaxSize() + .padding(paddingValues) ) { - val ( - imageCardView, tabLayout, viewPager, - compressButton, adView - ) = createRefs() + val (imageCardView , tabLayout , viewPager , compressButton , adView) = createRefs() Card( modifier = Modifier - .fillMaxWidth() - .constrainAs(imageCardView) { - top.linkTo(parent.top) - start.linkTo(parent.start) - end.linkTo(parent.end) - bottom.linkTo(tabLayout.top) - } - .padding(24.dp), + .fillMaxWidth() + .constrainAs(imageCardView) { + top.linkTo(parent.top) + start.linkTo(parent.start) + end.linkTo(parent.end) + bottom.linkTo(tabLayout.top) + } + .padding(24.dp) , ) { ImageDisplay(viewModel) } - TabRow( - selectedTabIndex = pagerState.currentPage, - modifier = Modifier - .constrainAs(tabLayout) { - top.linkTo(imageCardView.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - } - ) { - tabs.forEachIndexed { index, title -> - Tab( - text = { Text(title) }, - selected = pagerState.currentPage == index, + TabRow(selectedTabIndex = pagerState.currentPage , + modifier = Modifier.constrainAs(tabLayout) { + top.linkTo(imageCardView.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + }) { + tabs.forEachIndexed { index , title -> + Tab(text = { Text(title) } , + selected = pagerState.currentPage == index , onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } - } - ) + }) } } - HorizontalPager( - state = pagerState, - modifier = Modifier - .constrainAs(viewPager) { + HorizontalPager(state = pagerState , modifier = Modifier.constrainAs(viewPager) { top.linkTo(tabLayout.bottom) start.linkTo(parent.start) end.linkTo(parent.end) bottom.linkTo(compressButton.top) height = Dimension.fillToConstraints - } - ) { page -> + }) { page -> when (page) { - 0 -> QuickCompressScreen(viewModel) - 1 -> FileSizeScreen(viewModel) - 2 -> ManualModeScreen(viewModel) + 0 -> QuickCompressScreen(viewModel) + 1 -> FileSizeScreen(viewModel) + 2 -> ManualModeScreen(viewModel) } } - OutlinedButton( - onClick = { + OutlinedButton(onClick = { - }, - modifier = Modifier + } , modifier = Modifier .constrainAs(compressButton) { start.linkTo(parent.start) end.linkTo(parent.end) if (adsState.value) { bottom.linkTo(adView.top) - } else { + } + else { bottom.linkTo(parent.bottom) } } - .padding(12.dp) - ) { + .padding(12.dp)) { Text(stringResource(R.string.optimize_image)) } BannerAdsComposable( - modifier = Modifier - .constrainAs(adView) { - bottom.linkTo(parent.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, - dataStore = dataStore + modifier = Modifier.constrainAs(adView) { + bottom.linkTo(parent.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + } , dataStore = dataStore ) } } @@ -175,7 +161,7 @@ fun ImageOptimizerComposable(activity: ImageOptimizerActivity, viewModel: ImageO @Composable -fun ImageDisplay(viewModel: ImageOptimizerViewModel) { +fun ImageDisplay(viewModel : ImageOptimizerViewModel) { val state = viewModel.uiState.collectAsState() val showCompressedImage = remember { mutableStateOf(false) } @@ -187,20 +173,20 @@ fun ImageDisplay(viewModel: ImageOptimizerViewModel) { Box( modifier = Modifier - .fillMaxWidth() - .aspectRatio(1f), - contentAlignment = Alignment.Center + .fillMaxWidth() + .aspectRatio(1f) , contentAlignment = Alignment.Center ) { if (state.value.isLoading) { CircularProgressIndicator() - } else { + } + else { if (showCompressedImage.value) { state.value.compressedImageUri?.let { imageUri -> AsyncImage( - model = imageUri, - contentDescription = "Selected Image", - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.Crop, + model = imageUri , + contentDescription = "Selected Image" , + modifier = Modifier.fillMaxSize() , + contentScale = ContentScale.Crop , ) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerViewModel.kt index 88ac04a..57a2ed5 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/ImageOptimizerViewModel.kt @@ -23,35 +23,39 @@ import kotlinx.coroutines.withContext import java.io.File import java.io.FileOutputStream -class ImageOptimizerViewModel(application: Application) : AndroidViewModel(application) { +class ImageOptimizerViewModel(application : Application) : AndroidViewModel(application) { private val _uiState = MutableStateFlow(ImageOptimizerState()) val uiState = _uiState.asStateFlow() - private fun getAppContext(): Context = getApplication().applicationContext + private fun getAppContext() : Context = getApplication().applicationContext - suspend fun setQuickCompressValue(value: Int) { + suspend fun setQuickCompressValue(value : Int) { _uiState.emit(_uiState.value.copy(quickCompressValue = value)) compressImage() } - suspend fun setFileSize(size: Int) { + suspend fun setFileSize(size : Int) { _uiState.emit(_uiState.value.copy(fileSizeKB = size)) compressImage() } - suspend fun setManualCompressSettings(width: Int, height: Int, quality: Int) { + suspend fun setManualCompressSettings(width : Int , height : Int , quality : Int) { _uiState.emit( - _uiState.value.copy(manualWidth = width, manualHeight = height, manualQuality = quality) + _uiState.value.copy( + manualWidth = width , + manualHeight = height , + manualQuality = quality + ) ) compressImage() } - suspend fun onImageSelected(uri: Uri) { + suspend fun onImageSelected(uri : Uri) { _uiState.emit( _uiState.value.copy( - selectedImageUri = uri, - compressedImageUri = uri, // Initially show original image + selectedImageUri = uri , + compressedImageUri = uri , // Initially show original image ) ) @@ -60,12 +64,12 @@ class ImageOptimizerViewModel(application: Application) : AndroidViewModel(appli private fun compressImage() = viewModelScope.launch { _uiState.emit(_uiState.value.copy(isLoading = true)) val context = getAppContext() - val originalFile = _uiState.value.selectedImageUri?.let { getRealFileFromUri(context, it) } + val originalFile = _uiState.value.selectedImageUri?.let { getRealFileFromUri(context , it) } val currentTab = _uiState.value.currentTab val compressedFile = originalFile?.let { file -> withContext(Dispatchers.IO) { try { - Compressor.compress(context, file) { + Compressor.compress(context , file) { when (currentTab) { 0 -> { quality(_uiState.value.quickCompressValue) @@ -79,36 +83,33 @@ class ImageOptimizerViewModel(application: Application) : AndroidViewModel(appli 2 -> { resolution( - _uiState.value.manualWidth, - _uiState.value.manualHeight + _uiState.value.manualWidth , _uiState.value.manualHeight ) quality(_uiState.value.manualQuality) } } } - } catch (e: Exception) { + } catch (e : Exception) { null } } } - _uiState.emit( - _uiState.value.copy( - isLoading = false, - compressedImageUri = compressedFile?.let { Uri.fromFile(it) } - ?: _uiState.value.selectedImageUri, - ) - ) + _uiState.emit(_uiState.value.copy( + isLoading = false , + compressedImageUri = compressedFile?.let { Uri.fromFile(it) } + ?: _uiState.value.selectedImageUri , + )) } - private fun getRealFileFromUri(context: Context, uri: Uri): File? { + private fun getRealFileFromUri(context : Context , uri : Uri) : File? { if (uri.scheme == "content") { - val cursor: Cursor? = context.contentResolver.query(uri, null, null, null, null) + val cursor : Cursor? = context.contentResolver.query(uri , null , null , null , null) cursor?.use { if (it.moveToFirst()) { - val nameIndex: Int = it.getColumnIndex(OpenableColumns.DISPLAY_NAME) - val fileName: String = it.getString(nameIndex) - val file = File(context.cacheDir, fileName) + val nameIndex : Int = it.getColumnIndex(OpenableColumns.DISPLAY_NAME) + val fileName : String = it.getString(nameIndex) + val file = File(context.cacheDir , fileName) val inputStream = context.contentResolver.openInputStream(uri) inputStream?.use { stream -> val outputStream = FileOutputStream(file) @@ -117,8 +118,9 @@ class ImageOptimizerViewModel(application: Application) : AndroidViewModel(appli return file } } - } else if (uri.scheme == "file") { - return File(uri.path!!) + } + else if (uri.scheme == "file") { + return File(uri.path !!) } return null } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/FileSizeComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/FileSizeComposable.kt index 1f0cbab..ca7a73a 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/FileSizeComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/FileSizeComposable.kt @@ -28,7 +28,7 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -fun FileSizeScreen(viewModel: ImageOptimizerViewModel) { +fun FileSizeScreen(viewModel : ImageOptimizerViewModel) { val state = viewModel.uiState.collectAsState() var fileSizeText by remember { mutableStateOf(state.value.fileSizeKB.toString()) } var expanded by remember { mutableStateOf(false) } @@ -36,48 +36,38 @@ fun FileSizeScreen(viewModel: ImageOptimizerViewModel) { var selectedPresetSize by remember { mutableStateOf("") } val coroutineScope = rememberCoroutineScope() Column(modifier = Modifier.padding(16.dp)) { - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { expanded = !expanded } - ) { - OutlinedTextField( - value = fileSizeText, - onValueChange = { newValue -> - fileSizeText = newValue - coroutineScope.launch { - viewModel.setFileSize(newValue.toIntOrNull() ?: 0) - } - }, - label = { Text(stringResource(R.string.file_size)) }, - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - supportingText = { - Text(text = stringResource(R.string.enter_a_value)) - }, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, - isError = fileSizeText.isNotEmpty() && fileSizeText.toFloatOrNull() == null, - modifier = Modifier - .menuAnchor() - .fillMaxWidth() - .padding(top = 12.dp) + ExposedDropdownMenuBox(expanded = expanded , onExpandedChange = { expanded = ! expanded }) { + OutlinedTextField(value = fileSizeText , + onValueChange = { newValue -> + fileSizeText = newValue + coroutineScope.launch { + viewModel.setFileSize(newValue.toIntOrNull() ?: 0) + } + } , + label = { Text(stringResource(R.string.file_size)) } , + singleLine = true , + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) , + supportingText = { + Text(text = stringResource(R.string.enter_a_value)) + } , + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) } , + isError = fileSizeText.isNotEmpty() && fileSizeText.toFloatOrNull() == null , + modifier = Modifier + .menuAnchor() + .fillMaxWidth() + .padding(top = 12.dp) ) - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { + ExposedDropdownMenu(expanded = expanded , onDismissRequest = { expanded = false }) { presetSizes.forEach { size -> - DropdownMenuItem( - text = { Text("$size KB") }, - onClick = { - selectedPresetSize = size - fileSizeText = size - coroutineScope.launch { - viewModel.setFileSize(size.toIntOrNull() ?: 0) - } - expanded = false + DropdownMenuItem(text = { Text("$size KB") } , onClick = { + selectedPresetSize = size + fileSizeText = size + coroutineScope.launch { + viewModel.setFileSize(size.toIntOrNull() ?: 0) } - ) + expanded = false + }) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/ManualModeComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/ManualModeComposable.kt index 90e958b..9172248 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/ManualModeComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/ManualModeComposable.kt @@ -29,7 +29,7 @@ import com.d4rk.cleaner.ui.imageoptimizer.imageoptimizer.ImageOptimizerViewModel import kotlinx.coroutines.launch @Composable -fun ManualModeScreen(viewModel: ImageOptimizerViewModel) { +fun ManualModeScreen(viewModel : ImageOptimizerViewModel) { val state = viewModel.uiState.collectAsState() var widthText by remember { mutableStateOf(state.value.manualWidth.toString()) } var heightText by remember { mutableStateOf(state.value.manualHeight.toString()) } @@ -38,40 +38,40 @@ fun ManualModeScreen(viewModel: ImageOptimizerViewModel) { Column(modifier = Modifier.padding(16.dp)) { Row(modifier = Modifier.fillMaxWidth()) { OutlinedTextField( - value = widthText, + value = widthText , onValueChange = { newValue -> widthText = newValue coroutineScope.launch { viewModel.setManualCompressSettings( - newValue.toIntOrNull() ?: 0, - heightText.toIntOrNull() ?: 0, + newValue.toIntOrNull() ?: 0 , + heightText.toIntOrNull() ?: 0 , qualityValue.toInt() ) } - }, - label = { Text(stringResource(R.string.width)) }, - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + } , + label = { Text(stringResource(R.string.width)) } , + singleLine = true , + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) , modifier = Modifier - .weight(1f) - .padding(end = 8.dp) + .weight(1f) + .padding(end = 8.dp) ) OutlinedTextField( - value = heightText, + value = heightText , onValueChange = { newValue -> heightText = newValue coroutineScope.launch { viewModel.setManualCompressSettings( - widthText.toIntOrNull() ?: 0, - newValue.toIntOrNull() ?: 0, + widthText.toIntOrNull() ?: 0 , + newValue.toIntOrNull() ?: 0 , qualityValue.toInt() ) } - }, - label = { Text(stringResource(R.string.height)) }, - singleLine = true, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + } , + label = { Text(stringResource(R.string.height)) } , + singleLine = true , + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) , modifier = Modifier.weight(1f) ) } @@ -79,34 +79,31 @@ fun ManualModeScreen(viewModel: ImageOptimizerViewModel) { Spacer(modifier = Modifier.height(8.dp)) Text( - text = stringResource(R.string.quality), - style = MaterialTheme.typography.bodyLarge + text = stringResource(R.string.quality) , style = MaterialTheme.typography.bodyLarge ) Spacer(modifier = Modifier.height(4.dp)) Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically + modifier = Modifier.fillMaxWidth() , verticalAlignment = Alignment.CenterVertically ) { Text( text = stringResource( - R.string.image_compressor_percentage_format, - qualityValue.toInt() + R.string.image_compressor_percentage_format , qualityValue.toInt() ) ) Slider( - value = qualityValue, + value = qualityValue , onValueChange = { newValue -> coroutineScope.launch { qualityValue = newValue viewModel.setManualCompressSettings( - widthText.toIntOrNull() ?: 0, - heightText.toIntOrNull() ?: 0, + widthText.toIntOrNull() ?: 0 , + heightText.toIntOrNull() ?: 0 , newValue.toInt() ) } - }, + } , ) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/QuickCompressComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/QuickCompressComposable.kt index ccafda1..1731bea 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/QuickCompressComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imageoptimizer/tabs/QuickCompressComposable.kt @@ -28,7 +28,7 @@ import com.d4rk.cleaner.utils.imageoptimizer.getCompressionLevelFromSliderValue import kotlinx.coroutines.launch @Composable -fun QuickCompressScreen(viewModel: ImageOptimizerViewModel) { +fun QuickCompressScreen(viewModel : ImageOptimizerViewModel) { var sliderValue by remember { mutableFloatStateOf(50f) } val selectedCompression = getCompressionLevelFromSliderValue(sliderValue) val coroutineScope = rememberCoroutineScope() @@ -41,14 +41,11 @@ fun QuickCompressScreen(viewModel: ImageOptimizerViewModel) { sliderValue = compressionLevel.defaultPercentage.toFloat() viewModel.setQuickCompressValue(sliderValue.toInt()) } - }, - modifier = Modifier.weight(1f), - border = BorderStroke( - width = 1.dp, + } , modifier = Modifier.weight(1f) , border = BorderStroke( + width = 1.dp , color = if (selectedCompression == compressionLevel) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline - ), - colors = ButtonDefaults.outlinedButtonColors( + ) , colors = ButtonDefaults.outlinedButtonColors( contentColor = if (selectedCompression == compressionLevel) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface ) @@ -62,15 +59,12 @@ fun QuickCompressScreen(viewModel: ImageOptimizerViewModel) { Spacer(modifier = Modifier.height(16.dp)) Slider( - value = sliderValue, - onValueChange = { newValue -> + value = sliderValue , onValueChange = { newValue -> coroutineScope.launch { sliderValue = newValue viewModel.setQuickCompressValue(newValue.toInt()) } - }, - valueRange = 0f..100f, - steps = 99 + } , valueRange = 0f..100f , steps = 99 ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerActivity.kt index 078e56d..f31f828 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerActivity.kt @@ -16,33 +16,33 @@ import com.d4rk.cleaner.R import com.d4rk.cleaner.ui.settings.display.theme.style.AppTheme class ImagePickerActivity : AppCompatActivity() { - private val viewModel: ImagePickerViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { + private val viewModel : ImagePickerViewModel by viewModels() + override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { AppTheme { Surface( - modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background + modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { - ImagePickerComposable(this, viewModel) + ImagePickerComposable(this , viewModel) } } } } private val launcher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode == Activity.RESULT_OK && result.data != null) { - val selectedImageUri = result.data?.data - viewModel.setSelectedImageUri(selectedImageUri) + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK && result.data != null) { + val selectedImageUri = result.data?.data + viewModel.setSelectedImageUri(selectedImageUri) + } } - } fun selectImage() { val intent = Intent(Intent.ACTION_PICK) intent.type = "image/*" - val chooser = Intent.createChooser(intent, getString(R.string.select_image)) + val chooser = Intent.createChooser(intent , getString(R.string.select_image)) launcher.launch(chooser) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerComposable.kt index 5c13f91..b8cafd0 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerComposable.kt @@ -1,10 +1,16 @@ package com.d4rk.cleaner.ui.imageoptimizer.imagepicker import android.content.Intent +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.outlined.AddPhotoAlternate import androidx.compose.material.icons.outlined.ImageSearch import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton @@ -18,6 +24,7 @@ import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext @@ -33,8 +40,7 @@ import com.d4rk.cleaner.utils.compose.bounceClick @OptIn(ExperimentalMaterial3Api::class) @Composable fun ImagePickerComposable( - activity: ImagePickerActivity, - viewModel: ImagePickerViewModel + activity : ImagePickerActivity , viewModel : ImagePickerViewModel ) { val context = LocalContext.current val dataStore = DataStore.getInstance(context) @@ -43,64 +49,74 @@ fun ImagePickerComposable( LaunchedEffect(key1 = viewModel.selectedImageUri) { viewModel.selectedImageUri?.let { uri -> - val intent = Intent(context, ImageOptimizerActivity::class.java) - intent.putExtra("selectedImageUri", uri.toString()) + val intent = Intent(context , ImageOptimizerActivity::class.java) + intent.putExtra("selectedImageUri" , uri.toString()) activity.startActivity(intent) viewModel.setSelectedImageUri(null) } } - Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - LargeTopAppBar( - title = { Text(stringResource(R.string.image_optimizer)) }, - navigationIcon = { - IconButton(onClick = { - activity.finish() - }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) - } - }, - scrollBehavior = scrollBehavior + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { + LargeTopAppBar(title = { Text(stringResource(R.string.image_optimizer)) } , + navigationIcon = { + IconButton(onClick = { + activity.finish() + }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null) + } + } , + scrollBehavior = scrollBehavior ) }) { paddingValues -> ConstraintLayout( modifier = Modifier - .fillMaxSize() - .padding(paddingValues) + .fillMaxSize() + .padding(paddingValues) ) { - val (fab, adView) = createRefs() + val (fab , adView , imagePrompt) = createRefs() - ExtendedFloatingActionButton( - modifier = Modifier + Column(modifier = Modifier.constrainAs(imagePrompt) { + start.linkTo(parent.start) + end.linkTo(parent.end) + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + } , + verticalArrangement = Arrangement.Center , + horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + imageVector = Icons.Outlined.ImageSearch , + contentDescription = null , + modifier = Modifier.size(72.dp) + ) + Spacer(modifier = Modifier.height(16.dp)) + Text(text = stringResource(R.string.summary_select_image)) + } + + ExtendedFloatingActionButton(modifier = Modifier .padding(16.dp) .bounceClick() .constrainAs(fab) { end.linkTo(parent.end) if (adsState.value) { bottom.linkTo(adView.top) - } else { + } + else { bottom.linkTo(parent.bottom) } - }, - text = { Text(stringResource(R.string.choose_image)) }, - onClick = { - activity.selectImage() - }, - icon = { - Icon( - Icons.Outlined.ImageSearch, contentDescription = null - ) - } - ) + } , text = { Text(stringResource(R.string.choose_image)) } , onClick = { + activity.selectImage() + } , icon = { + Icon( + Icons.Outlined.AddPhotoAlternate , contentDescription = null + ) + }) BannerAdsComposable( - modifier = Modifier - .constrainAs(adView) { - bottom.linkTo(parent.bottom) - start.linkTo(parent.start) - end.linkTo(parent.end) - }, - dataStore = dataStore + modifier = Modifier.constrainAs(adView) { + bottom.linkTo(parent.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + } , dataStore = dataStore ) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerViewModel.kt index b6bfb5f..5faaf3b 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/imageoptimizer/imagepicker/ImagePickerViewModel.kt @@ -6,9 +6,9 @@ import androidx.lifecycle.ViewModel class ImagePickerViewModel : ViewModel() { private val _selectedImageUri = mutableStateOf(null) - val selectedImageUri: Uri? get() = _selectedImageUri.value + val selectedImageUri : Uri? get() = _selectedImageUri.value - fun setSelectedImageUri(uri: Uri?) { + fun setSelectedImageUri(uri : Uri?) { _selectedImageUri.value = uri } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt index 3562a20..08e1b19 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerComposable.kt @@ -98,7 +98,7 @@ fun MemoryManagerComposable() { LaunchedEffect(Unit) { viewModel.updateStorageInfo(context) viewModel.updateRamInfo(context) - if (!PermissionsUtils.hasStoragePermissions(context)) { + if (! PermissionsUtils.hasStoragePermissions(context)) { PermissionsUtils.requestStoragePermissions(context as Activity) } @@ -110,9 +110,9 @@ fun MemoryManagerComposable() { if (isLoading) { Box( modifier = Modifier - .fillMaxSize() - .animateContentSize() - .alpha(progressAlpha) , + .fillMaxSize() + .animateContentSize() + .alpha(progressAlpha) , contentAlignment = Alignment.Center ) { CircularProgressIndicator() @@ -121,12 +121,12 @@ fun MemoryManagerComposable() { else { Column( modifier = Modifier - .fillMaxSize() - .alpha(contentAlpha) + .fillMaxSize() + .alpha(contentAlpha) ) { CarouselLayout( - items = listOf(storageInfo, ramInfo), - peekPreviewWidth = 24.dp, + items = listOf(storageInfo , ramInfo) , + peekPreviewWidth = 24.dp , pagerState = pagerState ) { item -> when (item) { @@ -148,9 +148,9 @@ fun MemoryManagerComposable() { Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .padding(horizontal = 16.dp) , + .fillMaxWidth() + .animateContentSize() + .padding(horizontal = 16.dp) , verticalAlignment = Alignment.CenterVertically ) { Text( @@ -160,9 +160,8 @@ fun MemoryManagerComposable() { ) Spacer(modifier = Modifier.width(8.dp)) - IconButton( - modifier = Modifier.bounceClick() , - onClick = { viewModel.toggleListExpanded() }) { + IconButton(modifier = Modifier.bounceClick() , + onClick = { viewModel.toggleListExpanded() }) { Icon( imageVector = if (listExpanded) Icons.Outlined.ArrowDropDown else Icons.AutoMirrored.Filled.ArrowLeft , contentDescription = if (listExpanded) "Collapse" else "Expand" @@ -182,10 +181,10 @@ fun MemoryManagerComposable() { @OptIn(ExperimentalFoundationApi::class) @Composable fun CarouselLayout( - items: List, - peekPreviewWidth: Dp, - pagerState: PagerState, - itemContent: @Composable (item: T) -> Unit + items : List , + peekPreviewWidth : Dp , + pagerState : PagerState , + itemContent : @Composable (item : T) -> Unit ) { HorizontalPager( state = pagerState , @@ -202,49 +201,46 @@ fun CarouselLayout( val alpha = lerp(start = 0.5f , stop = 1f , fraction = 1f - pageOffset.coerceIn(0f , 1f)) Card(modifier = Modifier - .fillMaxWidth() - .graphicsLayer { - scaleX = scale - scaleY = scale - this.alpha = alpha - }) { + .fillMaxWidth() + .graphicsLayer { + scaleX = scale + scaleY = scale + this.alpha = alpha + }) { itemContent(items[page]) } } } @Composable -fun StorageInfoCard(storageInfo: StorageInfo) { +fun StorageInfoCard(storageInfo : StorageInfo) { Column( modifier = Modifier - .padding(16.dp) - .animateContentSize() + .padding(16.dp) + .animateContentSize() ) { Text( - text = stringResource(id = R.string.storage_information), - style = MaterialTheme.typography.headlineSmall, + text = stringResource(id = R.string.storage_information) , + style = MaterialTheme.typography.headlineSmall , fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.height(8.dp)) LinearProgressIndicator( - progress = { storageInfo.usedStorage.toFloat() / storageInfo.totalStorage.toFloat() }, + progress = { storageInfo.usedStorage.toFloat() / storageInfo.totalStorage.toFloat() } , modifier = Modifier - .fillMaxWidth() - .height(8.dp), - color = MaterialTheme.colorScheme.primary, + .fillMaxWidth() + .height(8.dp) , + color = MaterialTheme.colorScheme.primary , ) Spacer(modifier = Modifier.height(8.dp)) StorageInfoText( - label = stringResource(id = R.string.used), - size = storageInfo.usedStorage + label = stringResource(id = R.string.used) , size = storageInfo.usedStorage ) StorageInfoText( - label = stringResource(id = R.string.free), - size = storageInfo.freeStorage + label = stringResource(id = R.string.free) , size = storageInfo.freeStorage ) StorageInfoText( - label = stringResource(id = R.string.total), - size = storageInfo.totalStorage + label = stringResource(id = R.string.total) , size = storageInfo.totalStorage ) } } @@ -256,15 +252,15 @@ fun StorageBreakdownGrid(storageBreakdown : Map) { LazyColumn( modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .padding(horizontal = 16.dp) + .fillMaxWidth() + .animateContentSize() + .padding(horizontal = 16.dp) ) { items((items.size + chunkSize - 1) / chunkSize) { rowIndex -> Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize() + .fillMaxWidth() + .animateContentSize() ) { for (columnIndex in 0 until min(chunkSize , items.size - rowIndex * chunkSize)) { val index = rowIndex * chunkSize + columnIndex @@ -279,24 +275,24 @@ fun StorageBreakdownGrid(storageBreakdown : Map) { @Composable fun StorageBreakdownItem(icon : String , size : Long , modifier : Modifier = Modifier) { val storageIcons = mapOf( - stringResource(id = R.string.installed_apps) to Icons.Outlined.Apps, - stringResource(id = R.string.system) to Icons.Outlined.Android, - stringResource(id = R.string.music) to Icons.Outlined.MusicNote, - stringResource(id = R.string.images) to Icons.Outlined.Image, - stringResource(id = R.string.documents) to Icons.Outlined.FolderOpen, - stringResource(id = R.string.downloads) to Icons.Outlined.Download, - stringResource(id = R.string.other_files) to Icons.Outlined.FolderOpen, + stringResource(id = R.string.installed_apps) to Icons.Outlined.Apps , + stringResource(id = R.string.system) to Icons.Outlined.Android , + stringResource(id = R.string.music) to Icons.Outlined.MusicNote , + stringResource(id = R.string.images) to Icons.Outlined.Image , + stringResource(id = R.string.documents) to Icons.Outlined.FolderOpen , + stringResource(id = R.string.downloads) to Icons.Outlined.Download , + stringResource(id = R.string.other_files) to Icons.Outlined.FolderOpen , ) Card( modifier = modifier - .padding(vertical = 4.dp, horizontal = 4.dp) - .animateContentSize() + .padding(vertical = 4.dp , horizontal = 4.dp) + .animateContentSize() ) { Row( modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .padding(16.dp) , + .fillMaxWidth() + .animateContentSize() + .padding(16.dp) , verticalAlignment = Alignment.CenterVertically ) { Card( @@ -333,25 +329,28 @@ fun StorageInfoText(label : String , size : Long) { @Composable -fun RamInfoCard(ramInfo: RamInfo) { +fun RamInfoCard(ramInfo : RamInfo) { Column(modifier = Modifier.padding(16.dp)) { Text( - text = stringResource(id = R.string.ram_information), - style = MaterialTheme.typography.headlineSmall, + text = stringResource(id = R.string.ram_information) , + style = MaterialTheme.typography.headlineSmall , fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.height(8.dp)) StorageProgressBar( StorageInfo( - totalStorage = ramInfo.totalRam, - usedStorage = ramInfo.usedRam, + totalStorage = ramInfo.totalRam , + usedStorage = ramInfo.usedRam , freeStorage = ramInfo.availableRam ) ) Spacer(modifier = Modifier.height(8.dp)) - StorageInfoText(label = stringResource(id = R.string.used_ram), size = ramInfo.usedRam) - StorageInfoText(label = stringResource(id = R.string.free_ram), size = ramInfo.availableRam) - StorageInfoText(label = stringResource(id = R.string.total_ram), size = ramInfo.totalRam) + StorageInfoText(label = stringResource(id = R.string.used_ram) , size = ramInfo.usedRam) + StorageInfoText( + label = stringResource(id = R.string.free_ram) , + size = ramInfo.availableRam + ) + StorageInfoText(label = stringResource(id = R.string.total_ram) , size = ramInfo.totalRam) } } @@ -366,8 +365,8 @@ fun DotsIndicator( ) { LazyRow( modifier = modifier - .wrapContentWidth() - .wrapContentHeight() + .wrapContentWidth() + .wrapContentHeight() ) { items(totalDots) { index -> IndicatorDot( @@ -390,8 +389,8 @@ fun IndicatorDot( ) { Box( modifier = modifier - .size(size) - .clip(CircleShape) - .background(color) + .size(size) + .clip(CircleShape) + .background(color) ) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt index fb6cc15..7f2386e 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/memory/MemoryManagerViewModel.kt @@ -119,22 +119,25 @@ class MemoryManagerViewModel : ViewModel() { * @param context The application context. * @return A map containing storage usage by category (e.g., "Installed Apps", "Music", etc.). */ - private fun getStorageBreakdown(context: Context): Map { - val breakdown = mutableMapOf() + private fun getStorageBreakdown(context : Context) : Map { + val breakdown = mutableMapOf() val externalStoragePath = Environment.getExternalStorageDirectory().absolutePath breakdown[context.getString(R.string.installed_apps)] = getInstalledAppsSize(context) - breakdown[context.getString(R.string.system)] = getDirectorySize(Environment.getRootDirectory()) - breakdown[context.getString(R.string.music)] = getDirectorySize(File(externalStoragePath, "Music")) + breakdown[context.getString(R.string.system)] = + getDirectorySize(Environment.getRootDirectory()) + breakdown[context.getString(R.string.music)] = + getDirectorySize(File(externalStoragePath , "Music")) breakdown[context.getString(R.string.images)] = - getDirectorySize(File(externalStoragePath, "DCIM")) + getDirectorySize( - File( - externalStoragePath, - "Pictures" + getDirectorySize(File(externalStoragePath , "DCIM")) + getDirectorySize( + File( + externalStoragePath , "Pictures" + ) ) - ) - breakdown[context.getString(R.string.documents)] = getDirectorySize(File(externalStoragePath, "Documents")) - breakdown[context.getString(R.string.downloads)] = getDirectorySize(File(externalStoragePath, "Download")) + breakdown[context.getString(R.string.documents)] = + getDirectorySize(File(externalStoragePath , "Documents")) + breakdown[context.getString(R.string.downloads)] = + getDirectorySize(File(externalStoragePath , "Download")) breakdown[context.getString(R.string.other_files)] = getOtherFilesSize(breakdown) return breakdown diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsActivity.kt index fdd46bd..b84e368 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsActivity.kt @@ -11,13 +11,13 @@ import androidx.compose.ui.Modifier import com.d4rk.cleaner.ui.settings.display.theme.style.AppTheme class SettingsActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { + override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { AppTheme { Surface( - modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background + modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { SettingsComposable(this@SettingsActivity) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsComposable.kt index 5b140e9..58083d7 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/SettingsComposable.kt @@ -30,79 +30,88 @@ import com.d4rk.cleaner.ui.settings.advanced.AdvancedSettingsActivity import com.d4rk.cleaner.ui.settings.cleaning.CleaningSettingsActivity import com.d4rk.cleaner.ui.settings.display.DisplaySettingsActivity import com.d4rk.cleaner.ui.settings.privacy.PrivacySettingsActivity -import com.d4rk.cleaner.utils.compose.components.PreferenceItem import com.d4rk.cleaner.utils.IntentUtils +import com.d4rk.cleaner.utils.compose.components.PreferenceItem @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SettingsComposable(activity: SettingsActivity) { +fun SettingsComposable(activity : SettingsActivity) { val context = LocalContext.current val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) - Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - LargeTopAppBar(title = { Text(stringResource(R.string.settings)) }, navigationIcon = { + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { + LargeTopAppBar(title = { Text(stringResource(R.string.settings)) } , navigationIcon = { IconButton(onClick = { activity.finish() }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) + Icon(Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null) } - }, scrollBehavior = scrollBehavior) + } , scrollBehavior = scrollBehavior) }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues), + .fillMaxHeight() + .padding(paddingValues) , ) { item { - PreferenceItem(Icons.Outlined.Palette, - title = stringResource(R.string.display), - summary = stringResource(R.string.summary_preference_settings_display), - onClick = { - IntentUtils.openActivity(context, DisplaySettingsActivity::class.java) - }) + PreferenceItem(Icons.Outlined.Palette , + title = stringResource(R.string.display) , + summary = stringResource(R.string.summary_preference_settings_display) , + onClick = { + IntentUtils.openActivity( + context , + DisplaySettingsActivity::class.java + ) + }) } item { - PreferenceItem(Icons.Outlined.CleaningServices, - title = stringResource(R.string.cleaning), - summary = stringResource(R.string.summary_preference_settings_cleaning), - onClick = { - IntentUtils.openActivity( - context, CleaningSettingsActivity::class.java - ) - }) + PreferenceItem(Icons.Outlined.CleaningServices , + title = stringResource(R.string.cleaning) , + summary = stringResource(R.string.summary_preference_settings_cleaning) , + onClick = { + IntentUtils.openActivity( + context , CleaningSettingsActivity::class.java + ) + }) } item { - PreferenceItem(Icons.Outlined.Notifications, - title = stringResource(R.string.notifications), - summary = stringResource(R.string.summary_preference_settings_notifications), - onClick = { - IntentUtils.openAppNotificationSettings(context) - }) + PreferenceItem(Icons.Outlined.Notifications , + title = stringResource(R.string.notifications) , + summary = stringResource(R.string.summary_preference_settings_notifications) , + onClick = { + IntentUtils.openAppNotificationSettings(context) + }) } item { - PreferenceItem(Icons.Outlined.Build, - title = stringResource(R.string.advanced), - summary = stringResource(R.string.summary_preference_settings_advanced), - onClick = { - IntentUtils.openActivity( - context, AdvancedSettingsActivity::class.java - ) - }) + PreferenceItem(Icons.Outlined.Build , + title = stringResource(R.string.advanced) , + summary = stringResource(R.string.summary_preference_settings_advanced) , + onClick = { + IntentUtils.openActivity( + context , AdvancedSettingsActivity::class.java + ) + }) } item { - PreferenceItem(Icons.Outlined.SafetyCheck, - title = stringResource(R.string.security_and_privacy), - summary = stringResource(R.string.summary_preference_settings_privacy_and_security), - onClick = { - IntentUtils.openActivity(context, PrivacySettingsActivity::class.java) - }) + PreferenceItem(Icons.Outlined.SafetyCheck , + title = stringResource(R.string.security_and_privacy) , + summary = stringResource(R.string.summary_preference_settings_privacy_and_security) , + onClick = { + IntentUtils.openActivity( + context , + PrivacySettingsActivity::class.java + ) + }) } item { - PreferenceItem(Icons.Outlined.Info, - title = stringResource(R.string.about), - summary = stringResource(R.string.summary_preference_settings_about), - onClick = { - IntentUtils.openActivity(context, AboutSettingsActivity::class.java) - }) + PreferenceItem(Icons.Outlined.Info , + title = stringResource(R.string.about) , + summary = stringResource(R.string.summary_preference_settings_about) , + onClick = { + IntentUtils.openActivity( + context , + AboutSettingsActivity::class.java + ) + }) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/about/AboutSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/about/AboutSettingsComposable.kt index 7692c8e..ba30b16 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/about/AboutSettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/about/AboutSettingsComposable.kt @@ -24,9 +24,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.d4rk.cleaner.BuildConfig import com.d4rk.cleaner.R +import com.d4rk.cleaner.utils.IntentUtils import com.d4rk.cleaner.utils.compose.components.PreferenceCategoryItem import com.d4rk.cleaner.utils.compose.components.PreferenceItem -import com.d4rk.cleaner.utils.IntentUtils import com.google.android.gms.oss.licenses.OssLicensesMenuActivity @OptIn(ExperimentalMaterial3Api::class) @@ -46,8 +46,8 @@ fun AboutSettingsComposable(activity : AboutSettingsActivity) { }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues) , + .fillMaxHeight() + .padding(paddingValues) , ) { item { PreferenceCategoryItem(title = stringResource(R.string.app_info)) @@ -60,10 +60,13 @@ fun AboutSettingsComposable(activity : AboutSettingsActivity) { summary = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" ) PreferenceItem(title = stringResource(com.google.android.gms.oss.licenses.R.string.oss_license_title) , - summary = stringResource(R.string.summary_preference_settings_oss) , - onClick = { - IntentUtils.openActivity(context , OssLicensesMenuActivity::class.java) - }) + summary = stringResource(R.string.summary_preference_settings_oss) , + onClick = { + IntentUtils.openActivity( + context , + OssLicensesMenuActivity::class.java + ) + }) } item { PreferenceCategoryItem(title = stringResource(R.string.device_info)) @@ -77,12 +80,12 @@ fun AboutSettingsComposable(activity : AboutSettingsActivity) { ) PreferenceItem(title = stringResource(id = R.string.device_info) , - summary = version , - onClick = { - val clip = ClipData.newPlainText("text" , version) - clipboardManager.setPrimaryClip(clip) - // TODO: Show snackbar - }) + summary = version , + onClick = { + val clip = ClipData.newPlainText("text" , version) + clipboardManager.setPrimaryClip(clip) + // TODO: Show snackbar + }) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/advanced/AdvancedSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/advanced/AdvancedSettingsComposable.kt index 775419c..3bbb9e2 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/advanced/AdvancedSettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/advanced/AdvancedSettingsComposable.kt @@ -19,9 +19,9 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.d4rk.cleaner.R +import com.d4rk.cleaner.utils.IntentUtils import com.d4rk.cleaner.utils.compose.components.PreferenceCategoryItem import com.d4rk.cleaner.utils.compose.components.PreferenceItem -import com.d4rk.cleaner.utils.IntentUtils @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -41,19 +41,19 @@ fun AdvancedSettingsComposable(activity : AdvancedSettingsActivity) { }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues) , + .fillMaxHeight() + .padding(paddingValues) , ) { item { PreferenceCategoryItem(title = stringResource(R.string.error_reporting)) PreferenceItem(title = stringResource(R.string.bug_report) , - summary = stringResource(R.string.summary_preference_settings_bug_report) , - onClick = { - IntentUtils.openUrl( - context , - "https://github.com/D4rK7355608/${context.packageName}/issues/new" - ) - }) + summary = stringResource(R.string.summary_preference_settings_bug_report) , + onClick = { + IntentUtils.openUrl( + context , + "https://github.com/D4rK7355608/${context.packageName}/issues/new" + ) + }) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsActivity.kt index 55af79d..c2ffef4 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsActivity.kt @@ -11,13 +11,13 @@ import androidx.compose.ui.Modifier import com.d4rk.cleaner.ui.settings.display.theme.style.AppTheme class CleaningSettingsActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { + override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { AppTheme { Surface( - modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background + modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { CleaningSettingsComposable(this@CleaningSettingsActivity) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsComposable.kt index cdc060f..dbbbe11 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/cleaning/CleaningSettingsComposable.kt @@ -30,7 +30,7 @@ import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable -fun CleaningSettingsComposable(activity: CleaningSettingsActivity) { +fun CleaningSettingsComposable(activity : CleaningSettingsActivity) { val context = LocalContext.current val dataStore = DataStore.getInstance(context) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) @@ -44,61 +44,61 @@ fun CleaningSettingsComposable(activity: CleaningSettingsActivity) { val deleteVideoFiles by dataStore.deleteVideoFiles.collectAsState(initial = false) val deleteImageFiles by dataStore.deleteImageFiles.collectAsState(initial = false) val clipboardClean by dataStore.clipboardClean.collectAsState(initial = false) - Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - LargeTopAppBar(title = { Text(stringResource(R.string.cleaning)) }, navigationIcon = { + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { + LargeTopAppBar(title = { Text(stringResource(R.string.cleaning)) } , navigationIcon = { IconButton(onClick = { activity.finish() }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) + Icon(Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null) } - }, scrollBehavior = scrollBehavior) + } , scrollBehavior = scrollBehavior) }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues), + .fillMaxHeight() + .padding(paddingValues) , ) { item { PreferenceCategoryItem(title = stringResource(R.string.filters)) SwitchPreferenceItem( - title = stringResource(R.string.generic_filter), - summary = stringResource(R.string.summary_preference_settings_generic_filter), - checked = genericFilter, + title = stringResource(R.string.generic_filter) , + summary = stringResource(R.string.summary_preference_settings_generic_filter) , + checked = genericFilter , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveGenericFilter(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_empty_folders), - checked = deleteEmptyFolders, + title = stringResource(R.string.delete_empty_folders) , + checked = deleteEmptyFolders , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteEmptyFolders(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_archives), - summary = stringResource(R.string.summary_preference_settings_archive_filter), - checked = deleteArchives, + title = stringResource(R.string.delete_archives) , + summary = stringResource(R.string.summary_preference_settings_archive_filter) , + checked = deleteArchives , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteArchives(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_corpse_files), - summary = stringResource(R.string.summary_preference_settings_delete_corpse_files), - checked = deleteCorpseFiles, + title = stringResource(R.string.delete_corpse_files) , + summary = stringResource(R.string.summary_preference_settings_delete_corpse_files) , + checked = deleteCorpseFiles , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteCorpseFiles(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_apk_files), - summary = stringResource(R.string.summary_preference_settings_delete_apk_files), - checked = deleteApkFiles, + title = stringResource(R.string.delete_apk_files) , + summary = stringResource(R.string.summary_preference_settings_delete_apk_files) , + checked = deleteApkFiles , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteApkFiles(isChecked) @@ -109,36 +109,36 @@ fun CleaningSettingsComposable(activity: CleaningSettingsActivity) { item { PreferenceCategoryItem(title = stringResource(R.string.media)) SwitchPreferenceItem( - title = stringResource(R.string.delete_audio), - summary = stringResource(R.string.summary_preference_settings_delete_audio), - checked = deleteAudioFiles, + title = stringResource(R.string.delete_audio) , + summary = stringResource(R.string.summary_preference_settings_delete_audio) , + checked = deleteAudioFiles , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteAudioFiles(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_video), - summary = stringResource(R.string.summary_preference_settings_delete_video), - checked = deleteVideoFiles, + title = stringResource(R.string.delete_video) , + summary = stringResource(R.string.summary_preference_settings_delete_video) , + checked = deleteVideoFiles , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteVideoFiles(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_images), - summary = stringResource(R.string.summary_preference_settings_delete_images), - checked = deleteImageFiles, + title = stringResource(R.string.delete_images) , + summary = stringResource(R.string.summary_preference_settings_delete_images) , + checked = deleteImageFiles , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteImageFiles(isChecked) } } SwitchPreferenceItem( - title = stringResource(R.string.delete_invalid_media), - summary = stringResource(R.string.summary_preference_settings_delete_invalid_media), - checked = deleteInvalidMedia, + title = stringResource(R.string.delete_invalid_media) , + summary = stringResource(R.string.summary_preference_settings_delete_invalid_media) , + checked = deleteInvalidMedia , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveDeleteInvalidMedia(isChecked) @@ -149,8 +149,8 @@ fun CleaningSettingsComposable(activity: CleaningSettingsActivity) { item { PreferenceCategoryItem(title = stringResource(R.string.scanner)) SwitchPreferenceItem( - title = stringResource(R.string.clipboard_clean), - checked = clipboardClean, + title = stringResource(R.string.clipboard_clean) , + checked = clipboardClean , ) { isChecked -> CoroutineScope(Dispatchers.IO).launch { dataStore.saveClipboardClean(isChecked) diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/DisplaySettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/DisplaySettingsComposable.kt index fcc3783..5c7ffb9 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/DisplaySettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/DisplaySettingsComposable.kt @@ -34,11 +34,11 @@ import com.d4rk.cleaner.R import com.d4rk.cleaner.data.datastore.DataStore import com.d4rk.cleaner.ui.dialogs.LanguageDialog import com.d4rk.cleaner.ui.settings.display.theme.ThemeSettingsActivity +import com.d4rk.cleaner.utils.IntentUtils import com.d4rk.cleaner.utils.compose.components.PreferenceCategoryItem import com.d4rk.cleaner.utils.compose.components.PreferenceItem import com.d4rk.cleaner.utils.compose.components.SwitchPreferenceItem import com.d4rk.cleaner.utils.compose.components.SwitchPreferenceItemWithDivider -import com.d4rk.cleaner.utils.IntentUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -73,36 +73,36 @@ fun DisplaySettingsComposable(activity : DisplaySettingsActivity) { }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues) , + .fillMaxHeight() + .padding(paddingValues) , ) { item { PreferenceCategoryItem(title = stringResource(R.string.appearance)) SwitchPreferenceItemWithDivider(title = stringResource(R.string.dark_theme) , - summary = themeSummary , - checked = switchState.value , - onCheckedChange = { isChecked -> - switchState.value = isChecked - } , - onSwitchClick = { isChecked -> - scope.launch(Dispatchers.IO) { - if (isChecked) { - dataStore.saveThemeMode(darkModeString) - dataStore.themeModeState.value = - darkModeString - } - else { - dataStore.saveThemeMode(lightModeString) - dataStore.themeModeState.value = - lightModeString - } - } - } , - onClick = { - IntentUtils.openActivity( - context , ThemeSettingsActivity::class.java - ) - }) + summary = themeSummary , + checked = switchState.value , + onCheckedChange = { isChecked -> + switchState.value = isChecked + } , + onSwitchClick = { isChecked -> + scope.launch(Dispatchers.IO) { + if (isChecked) { + dataStore.saveThemeMode(darkModeString) + dataStore.themeModeState.value = + darkModeString + } + else { + dataStore.saveThemeMode(lightModeString) + dataStore.themeModeState.value = + lightModeString + } + } + } , + onClick = { + IntentUtils.openActivity( + context , ThemeSettingsActivity::class.java + ) + }) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { SwitchPreferenceItem( @@ -119,49 +119,49 @@ fun DisplaySettingsComposable(activity : DisplaySettingsActivity) { item { PreferenceCategoryItem(title = stringResource(R.string.language)) PreferenceItem(title = stringResource(R.string.language) , - summary = stringResource(id = R.string.summary_preference_settings_language) , - onClick = { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - val localeIntent = - Intent(Settings.ACTION_APP_LOCALE_SETTINGS).setData( - Uri.fromParts( - "package" , context.packageName , null - ) - ) - val detailsIntent = - Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData( - Uri.fromParts( - "package" , context.packageName , null - ) - ) - when { - context.packageManager.resolveActivity( - localeIntent , 0 - ) != null -> context.startActivity(localeIntent) + summary = stringResource(id = R.string.summary_preference_settings_language) , + onClick = { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + val localeIntent = + Intent(Settings.ACTION_APP_LOCALE_SETTINGS).setData( + Uri.fromParts( + "package" , context.packageName , null + ) + ) + val detailsIntent = + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData( + Uri.fromParts( + "package" , context.packageName , null + ) + ) + when { + context.packageManager.resolveActivity( + localeIntent , 0 + ) != null -> context.startActivity(localeIntent) - context.packageManager.resolveActivity( - detailsIntent , 0 - ) != null -> context.startActivity(detailsIntent) + context.packageManager.resolveActivity( + detailsIntent , 0 + ) != null -> context.startActivity(detailsIntent) - else -> { - showLanguageDialog = true - } - } - } - else { - showLanguageDialog = true - } - }) + else -> { + showLanguageDialog = true + } + } + } + else { + showLanguageDialog = true + } + }) if (showLanguageDialog) { LanguageDialog(dataStore = dataStore , - onDismiss = { showLanguageDialog = false } , - onLanguageSelected = { newLanguageCode -> - AppCompatDelegate.setApplicationLocales( - LocaleListCompat.forLanguageTags( - newLanguageCode - ) - ) - }) + onDismiss = { showLanguageDialog = false } , + onLanguageSelected = { newLanguageCode -> + AppCompatDelegate.setApplicationLocales( + LocaleListCompat.forLanguageTags( + newLanguageCode + ) + ) + }) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/ThemeSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/ThemeSettingsComposable.kt index 366bd04..07e554b 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/ThemeSettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/ThemeSettingsComposable.kt @@ -66,8 +66,8 @@ fun ThemeSettingsComposable(activity : ThemeSettingsActivity) { Box(modifier = Modifier.fillMaxSize()) { LazyColumn( modifier = Modifier - .fillMaxSize() - .padding(paddingValues) , + .fillMaxSize() + .padding(paddingValues) , ) { item { SwitchCardComposable( @@ -81,8 +81,8 @@ fun ThemeSettingsComposable(activity : ThemeSettingsActivity) { item { Column( modifier = Modifier - .fillMaxWidth() - .padding(24.dp) + .fillMaxWidth() + .padding(24.dp) ) { themeOptions.forEach { text -> Row( @@ -107,8 +107,8 @@ fun ThemeSettingsComposable(activity : ThemeSettingsActivity) { item { Column( modifier = Modifier - .fillMaxWidth() - .padding(24.dp) + .fillMaxWidth() + .padding(24.dp) ) { Icon(imageVector = Icons.Outlined.Info , contentDescription = null) Spacer(modifier = Modifier.height(24.dp)) diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Theme.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Theme.kt index b333d57..4dd8c8d 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Theme.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Theme.kt @@ -118,9 +118,9 @@ private fun getColorScheme( isDarkTheme : Boolean , isAmoledMode : Boolean , isDynamicColors : Boolean , context : Context ) : ColorScheme { val dynamicDark = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) dynamicDarkColorScheme(context) else darkScheme + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) dynamicDarkColorScheme(context) else darkScheme val dynamicLight = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) dynamicLightColorScheme(context) else lightScheme + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) dynamicLightColorScheme(context) else lightScheme return when { isAmoledMode && isDarkTheme && isDynamicColors -> dynamicDark.copy( @@ -163,11 +163,11 @@ fun AppTheme( val window = (view.context as Activity).window window.statusBarColor = Color.Transparent.toArgb() WindowCompat.getInsetsController(window , view).isAppearanceLightStatusBars = - ! isDarkTheme + ! isDarkTheme } } MaterialTheme( - colorScheme = colorScheme , typography = Typography, content = content + colorScheme = colorScheme , typography = Typography , content = content ) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Type.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Type.kt index 453a646..0c3ed63 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Type.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/display/theme/style/Type.kt @@ -8,10 +8,10 @@ import androidx.compose.ui.unit.sp val Typography = Typography( bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, + fontFamily = FontFamily.Default , + fontWeight = FontWeight.Normal , + fontSize = 16.sp , + lineHeight = 24.sp , letterSpacing = 0.5.sp ) ) \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/PrivacySettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/PrivacySettingsComposable.kt index 74f3cc9..fbd2737 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/PrivacySettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/PrivacySettingsComposable.kt @@ -22,9 +22,9 @@ import com.d4rk.cleaner.R import com.d4rk.cleaner.ui.settings.privacy.ads.AdsSettingsActivity import com.d4rk.cleaner.ui.settings.privacy.permissions.PermissionsSettingsActivity import com.d4rk.cleaner.ui.settings.privacy.usage.UsageAndDiagnosticsActivity +import com.d4rk.cleaner.utils.IntentUtils import com.d4rk.cleaner.utils.compose.components.PreferenceCategoryItem import com.d4rk.cleaner.utils.compose.components.PreferenceItem -import com.d4rk.cleaner.utils.IntentUtils @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -33,85 +33,88 @@ fun PrivacySettingsComposable(activity : PrivacySettingsActivity) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { LargeTopAppBar(title = { Text(stringResource(R.string.security_and_privacy)) } , - navigationIcon = { - IconButton(onClick = { - activity.finish() - }) { - Icon( - Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null - ) - } - } , - scrollBehavior = scrollBehavior) + navigationIcon = { + IconButton(onClick = { + activity.finish() + }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null + ) + } + } , + scrollBehavior = scrollBehavior) }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues) , + .fillMaxHeight() + .padding(paddingValues) , ) { item { PreferenceCategoryItem(title = stringResource(R.string.privacy)) PreferenceItem(title = stringResource(R.string.privacy_policy) , - summary = stringResource(id = R.string.summary_preference_settings_privacy_policy) , - onClick = { - IntentUtils.openUrl( - context , - "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy" - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_privacy_policy) , + onClick = { + IntentUtils.openUrl( + context , + "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy" + ) + }) PreferenceItem(title = stringResource(R.string.terms_of_service) , - summary = stringResource(id = R.string.summary_preference_settings_terms_of_service) , - onClick = { - IntentUtils.openUrl( - context , - "https://sites.google.com/view/d4rk7355608/more/apps/terms-of-service" - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_terms_of_service) , + onClick = { + IntentUtils.openUrl( + context , + "https://sites.google.com/view/d4rk7355608/more/apps/terms-of-service" + ) + }) PreferenceItem(title = stringResource(R.string.code_of_conduct) , - summary = stringResource(id = R.string.summary_preference_settings_code_of_conduct) , - onClick = { - IntentUtils.openUrl( - context , - "https://sites.google.com/view/d4rk7355608/more/code-of-conduct" - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_code_of_conduct) , + onClick = { + IntentUtils.openUrl( + context , + "https://sites.google.com/view/d4rk7355608/more/code-of-conduct" + ) + }) PreferenceItem(title = stringResource(R.string.permissions) , - summary = stringResource(id = R.string.summary_preference_settings_permissions) , - onClick = { - IntentUtils.openActivity( - context , PermissionsSettingsActivity::class.java - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_permissions) , + onClick = { + IntentUtils.openActivity( + context , PermissionsSettingsActivity::class.java + ) + }) PreferenceItem(title = stringResource(R.string.ads) , - summary = stringResource(id = R.string.summary_preference_settings_ads) , - onClick = { - IntentUtils.openActivity( - context , AdsSettingsActivity::class.java - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_ads) , + onClick = { + IntentUtils.openActivity( + context , AdsSettingsActivity::class.java + ) + }) PreferenceItem(title = stringResource(R.string.usage_and_diagnostics) , - summary = stringResource(id = R.string.summary_preference_settings_usage_and_diagnostics) , - onClick = { - IntentUtils.openActivity( - context , UsageAndDiagnosticsActivity::class.java - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_usage_and_diagnostics) , + onClick = { + IntentUtils.openActivity( + context , UsageAndDiagnosticsActivity::class.java + ) + }) } item { PreferenceCategoryItem(title = stringResource(R.string.legal)) PreferenceItem(title = stringResource(R.string.legal_notices) , - summary = stringResource(id = R.string.summary_preference_settings_legal_notices) , - onClick = { - IntentUtils.openUrl( - context , - "https://sites.google.com/view/d4rk7355608/more/apps/legal-notices" - ) - }) + summary = stringResource(id = R.string.summary_preference_settings_legal_notices) , + onClick = { + IntentUtils.openUrl( + context , + "https://sites.google.com/view/d4rk7355608/more/apps/legal-notices" + ) + }) PreferenceItem(title = stringResource(R.string.license) , - summary = stringResource(R.string.summary_preference_settings_license) , - onClick = { - IntentUtils.openUrl(context , "https://www.gnu.org/licenses/gpl-3.0") - }) + summary = stringResource(R.string.summary_preference_settings_license) , + onClick = { + IntentUtils.openUrl( + context , + "https://www.gnu.org/licenses/gpl-3.0" + ) + }) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/ads/AdsSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/ads/AdsSettingsComposable.kt index 28ddb68..18995db 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/ads/AdsSettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/ads/AdsSettingsComposable.kt @@ -35,9 +35,9 @@ import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import com.d4rk.cleaner.R import com.d4rk.cleaner.data.datastore.DataStore +import com.d4rk.cleaner.utils.IntentUtils import com.d4rk.cleaner.utils.compose.components.PreferenceItem import com.d4rk.cleaner.utils.compose.components.SwitchCardComposable -import com.d4rk.cleaner.utils.IntentUtils import com.google.android.ump.ConsentRequestParameters import com.google.android.ump.UserMessagingPlatform import kotlinx.coroutines.Dispatchers @@ -65,8 +65,8 @@ fun AdsSettingsComposable(activity : AdsSettingsActivity) { Box(modifier = Modifier.fillMaxSize()) { LazyColumn( modifier = Modifier - .fillMaxSize() - .padding(innerPadding) , + .fillMaxSize() + .padding(innerPadding) , ) { item { SwitchCardComposable( @@ -80,29 +80,29 @@ fun AdsSettingsComposable(activity : AdsSettingsActivity) { item { Box(modifier = Modifier.padding(horizontal = 8.dp)) { PreferenceItem(title = stringResource(R.string.personalized_ads) , - enabled = switchState.value , - summary = stringResource(id = R.string.summary_ads_personalized_ads) , - onClick = { - val params = ConsentRequestParameters.Builder() - .setTagForUnderAgeOfConsent(false).build() - val consentInformation = - UserMessagingPlatform.getConsentInformation( - context - ) - consentInformation.requestConsentInfoUpdate(activity , - params , - { - activity.openForm() - } , - {}) - }) + enabled = switchState.value , + summary = stringResource(id = R.string.summary_ads_personalized_ads) , + onClick = { + val params = ConsentRequestParameters.Builder() + .setTagForUnderAgeOfConsent(false).build() + val consentInformation = + UserMessagingPlatform.getConsentInformation( + context + ) + consentInformation.requestConsentInfoUpdate(activity , + params , + { + activity.openForm() + } , + {}) + }) } } item { Column( modifier = Modifier - .fillMaxWidth() - .padding(24.dp) + .fillMaxWidth() + .padding(24.dp) ) { Icon(imageVector = Icons.Outlined.Info , contentDescription = null) Spacer(modifier = Modifier.height(24.dp)) @@ -125,9 +125,9 @@ fun AdsSettingsComposable(activity : AdsSettingsActivity) { } ClickableText(text = annotatedString , onClick = { offset -> annotatedString.getStringAnnotations("URL" , offset , offset) - .firstOrNull()?.let { annotation -> - IntentUtils.openUrl(context , annotation.item) - } + .firstOrNull()?.let { annotation -> + IntentUtils.openUrl(context , annotation.item) + } }) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt index 0d16e2d..a53733d 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt @@ -23,112 +23,108 @@ import com.d4rk.cleaner.utils.compose.components.PreferenceItem @OptIn(ExperimentalMaterial3Api::class) @Composable -fun PermissionsSettingsComposable(activity: PermissionsSettingsActivity) { +fun PermissionsSettingsComposable(activity : PermissionsSettingsActivity) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) - Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - LargeTopAppBar( - title = { Text(stringResource(R.string.permissions)) }, - navigationIcon = { - IconButton(onClick = { - activity.finish() - }) { - Icon( - Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = null - ) - } - }, - scrollBehavior = scrollBehavior + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { + LargeTopAppBar(title = { Text(stringResource(R.string.permissions)) } , navigationIcon = { + IconButton(onClick = { + activity.finish() + }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null + ) + } + } , scrollBehavior = scrollBehavior ) }) { paddingValues -> LazyColumn( modifier = Modifier - .fillMaxHeight() - .padding(paddingValues), + .fillMaxHeight() + .padding(paddingValues) , ) { item { PreferenceCategoryItem(title = stringResource(R.string.normal)) PreferenceItem( - title = stringResource(R.string.ad_id), - summary = stringResource(R.string.summary_preference_permissions_ad_id), + title = stringResource(R.string.ad_id) , + summary = stringResource(R.string.summary_preference_permissions_ad_id) , ) PreferenceItem( - title = stringResource(R.string.internet), - summary = stringResource(R.string.summary_preference_permissions_internet), + title = stringResource(R.string.internet) , + summary = stringResource(R.string.summary_preference_permissions_internet) , ) PreferenceItem( - title = stringResource(R.string.post_notifications), - summary = stringResource(R.string.summary_preference_permissions_post_notifications), + title = stringResource(R.string.post_notifications) , + summary = stringResource(R.string.summary_preference_permissions_post_notifications) , ) } item { PreferenceCategoryItem(title = stringResource(R.string.runtime)) PreferenceItem( - title = stringResource(R.string.access_network_state), - summary = stringResource(R.string.summary_preference_permissions_access_network_state), + title = stringResource(R.string.access_network_state) , + summary = stringResource(R.string.summary_preference_permissions_access_network_state) , ) PreferenceItem( - title = stringResource(R.string.access_notification_policy), - summary = stringResource(R.string.summary_preference_permissions_access_notification_policy), + title = stringResource(R.string.access_notification_policy) , + summary = stringResource(R.string.summary_preference_permissions_access_notification_policy) , ) PreferenceItem( - title = stringResource(R.string.billing), - summary = stringResource(R.string.summary_preference_permissions_billing), + title = stringResource(R.string.billing) , + summary = stringResource(R.string.summary_preference_permissions_billing) , ) PreferenceItem( - title = stringResource(R.string.check_license), - summary = stringResource(R.string.summary_preference_permissions_check_license), + title = stringResource(R.string.check_license) , + summary = stringResource(R.string.summary_preference_permissions_check_license) , ) PreferenceItem( - title = stringResource(R.string.foreground_service), - summary = stringResource(R.string.summary_preference_permissions_foreground_service), + title = stringResource(R.string.foreground_service) , + summary = stringResource(R.string.summary_preference_permissions_foreground_service) , ) PreferenceItem( - title = stringResource(R.string.request_delete_packages), - summary = stringResource(R.string.summary_preference_permissions_request_delete_packages), + title = stringResource(R.string.request_delete_packages) , + summary = stringResource(R.string.summary_preference_permissions_request_delete_packages) , ) } item { PreferenceCategoryItem(title = stringResource(R.string.storage)) PreferenceItem( - title = stringResource(R.string.access_media_location), - summary = stringResource(R.string.summary_preference_permissions_access_media_location), + title = stringResource(R.string.access_media_location) , + summary = stringResource(R.string.summary_preference_permissions_access_media_location) , ) PreferenceItem( - title = stringResource(R.string.action_open_document_tree), - summary = stringResource(R.string.summary_preference_permissions_action_open_document_tree), + title = stringResource(R.string.action_open_document_tree) , + summary = stringResource(R.string.summary_preference_permissions_action_open_document_tree) , ) PreferenceItem( - title = stringResource(R.string.manage_external_storage), - summary = stringResource(R.string.summary_preference_permissions_manage_external_storage), + title = stringResource(R.string.manage_external_storage) , + summary = stringResource(R.string.summary_preference_permissions_manage_external_storage) , ) PreferenceItem( - title = stringResource(R.string.package_usage_stats), - summary = stringResource(R.string.summary_preference_permissions_package_usage_stats), + title = stringResource(R.string.package_usage_stats) , + summary = stringResource(R.string.summary_preference_permissions_package_usage_stats) , ) PreferenceItem( - title = stringResource(R.string.query_all_packages), - summary = stringResource(R.string.summary_preference_permissions_query_all_packages), + title = stringResource(R.string.query_all_packages) , + summary = stringResource(R.string.summary_preference_permissions_query_all_packages) , ) PreferenceItem( - title = stringResource(R.string.read_external_storage), - summary = stringResource(R.string.summary_preference_permissions_read_external_storage), + title = stringResource(R.string.read_external_storage) , + summary = stringResource(R.string.summary_preference_permissions_read_external_storage) , ) PreferenceItem( - title = stringResource(R.string.read_media_audio), - summary = stringResource(R.string.summary_preference_permissions_read_media_audio), + title = stringResource(R.string.read_media_audio) , + summary = stringResource(R.string.summary_preference_permissions_read_media_audio) , ) PreferenceItem( - title = stringResource(R.string.read_media_images), - summary = stringResource(R.string.summary_preference_permissions_read_media_images), + title = stringResource(R.string.read_media_images) , + summary = stringResource(R.string.summary_preference_permissions_read_media_images) , ) PreferenceItem( - title = stringResource(R.string.read_media_video), - summary = stringResource(R.string.summary_preference_permissions_read_media_video), + title = stringResource(R.string.read_media_video) , + summary = stringResource(R.string.summary_preference_permissions_read_media_video) , ) PreferenceItem( - title = stringResource(R.string.write_external_storage), - summary = stringResource(R.string.summary_preference_permissions_write_external_storage), + title = stringResource(R.string.write_external_storage) , + summary = stringResource(R.string.summary_preference_permissions_write_external_storage) , ) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt index 81447a8..b60b38c 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt @@ -35,8 +35,8 @@ import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import com.d4rk.cleaner.R import com.d4rk.cleaner.data.datastore.DataStore -import com.d4rk.cleaner.utils.compose.components.SwitchCardComposable import com.d4rk.cleaner.utils.IntentUtils +import com.d4rk.cleaner.utils.compose.components.SwitchCardComposable import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -50,22 +50,22 @@ fun UsageAndDiagnosticsComposable(activity : UsageAndDiagnosticsActivity) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { LargeTopAppBar(title = { Text(stringResource(R.string.usage_and_diagnostics)) } , - navigationIcon = { - IconButton(onClick = { - activity.finish() - }) { - Icon( - Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null - ) - } - } , - scrollBehavior = scrollBehavior) + navigationIcon = { + IconButton(onClick = { + activity.finish() + }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null + ) + } + } , + scrollBehavior = scrollBehavior) }) { innerPadding -> Box(modifier = Modifier.fillMaxSize()) { LazyColumn( modifier = Modifier - .fillMaxSize() - .padding(innerPadding) , + .fillMaxSize() + .padding(innerPadding) , ) { item { SwitchCardComposable( @@ -80,8 +80,8 @@ fun UsageAndDiagnosticsComposable(activity : UsageAndDiagnosticsActivity) { item { Column( modifier = Modifier - .fillMaxWidth() - .padding(24.dp) + .fillMaxWidth() + .padding(24.dp) ) { Icon(imageVector = Icons.Outlined.Info , contentDescription = null) Spacer(modifier = Modifier.height(24.dp)) @@ -104,9 +104,9 @@ fun UsageAndDiagnosticsComposable(activity : UsageAndDiagnosticsActivity) { } ClickableText(text = annotatedString , onClick = { offset -> annotatedString.getStringAnnotations("URL" , offset , offset) - .firstOrNull()?.let { annotation -> - IntentUtils.openUrl(context , annotation.item) - } + .firstOrNull()?.let { annotation -> + IntentUtils.openUrl(context , annotation.item) + } }) } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/startup/StartupComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/startup/StartupComposable.kt index 7718741..86eb121 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/startup/StartupComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/startup/StartupComposable.kt @@ -45,12 +45,12 @@ import com.d4rk.cleaner.utils.compose.bounceClick @OptIn(ExperimentalMaterial3Api::class) @Composable -fun StartupComposable(activity: StartupActivity) { +fun StartupComposable(activity : StartupActivity) { val context = LocalContext.current val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) val fabEnabled = remember { mutableStateOf(false) } LaunchedEffect(context) { - if (!PermissionsUtils.hasNotificationPermission(context)) { + if (! PermissionsUtils.hasNotificationPermission(context)) { PermissionsUtils.requestNotificationPermission(context as Activity) } activity.consentFormShown.collect { shown -> @@ -58,81 +58,81 @@ fun StartupComposable(activity: StartupActivity) { } } - Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { LargeTopAppBar( - title = { Text(stringResource(R.string.welcome)) }, - scrollBehavior = scrollBehavior + title = { Text(stringResource(R.string.welcome)) } , scrollBehavior = scrollBehavior ) }) { innerPadding -> Box( modifier = Modifier - .fillMaxSize() - .padding(24.dp) - .safeDrawingPadding() + .fillMaxSize() + .padding(24.dp) + .safeDrawingPadding() ) { LazyColumn( modifier = Modifier - .fillMaxSize() - .padding(innerPadding), + .fillMaxSize() + .padding(innerPadding) , ) { item { Image( - painter = painterResource(id = R.drawable.il_startup), + painter = painterResource(id = R.drawable.il_startup) , contentDescription = null ) Icon( - Icons.Outlined.Info, contentDescription = null + Icons.Outlined.Info , contentDescription = null ) } item { Text( - text = stringResource(R.string.summary_browse_terms_of_service_and_privacy_policy), - modifier = Modifier.padding(top = 24.dp, bottom = 24.dp) + text = stringResource(R.string.summary_browse_terms_of_service_and_privacy_policy) , + modifier = Modifier.padding(top = 24.dp , bottom = 24.dp) ) val annotatedString = buildAnnotatedString { withStyle( style = SpanStyle( - color = MaterialTheme.colorScheme.primary, + color = MaterialTheme.colorScheme.primary , textDecoration = TextDecoration.Underline ) ) { append(stringResource(R.string.browse_terms_of_service_and_privacy_policy)) } addStringAnnotation( - tag = "URL", - annotation = "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy", - start = 0, + tag = "URL" , + annotation = "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy" , + start = 0 , end = stringResource(R.string.browse_terms_of_service_and_privacy_policy).length ) } - ClickableText(text = annotatedString, onClick = { offset -> - annotatedString.getStringAnnotations("URL", offset, offset).firstOrNull() - ?.let { annotation -> - IntentUtils.openUrl(context, annotation.item) - } + ClickableText(text = annotatedString , onClick = { offset -> + annotatedString.getStringAnnotations("URL" , offset , offset).firstOrNull() + ?.let { annotation -> + IntentUtils.openUrl(context , annotation.item) + } }) } } ExtendedFloatingActionButton(modifier = Modifier - .align(Alignment.BottomEnd) - .bounceClick(), - containerColor = if (fabEnabled.value) { - FloatingActionButtonDefaults.containerColor - } else { - Gray - }, - text = { Text(stringResource(R.string.agree)) }, - onClick = { - IntentUtils.openActivity( - context , MainActivity::class.java - ) - }, - icon = { - Icon( - Icons.Outlined.CheckCircle, - contentDescription = null - ) - }) + .align(Alignment.BottomEnd) + .bounceClick() , + containerColor = if (fabEnabled.value) { + FloatingActionButtonDefaults.containerColor + } + else { + Gray + } , + text = { Text(stringResource(R.string.agree)) } , + onClick = { + IntentUtils.openActivity( + context , MainActivity::class.java + ) + } , + icon = { + Icon( + Icons.Outlined.CheckCircle , + contentDescription = null + ) + }) } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportActivity.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportActivity.kt index 8e5b4c0..c3b414d 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportActivity.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportActivity.kt @@ -17,18 +17,17 @@ import com.android.billingclient.api.SkuDetails import com.d4rk.cleaner.ui.settings.display.theme.style.AppTheme class SupportActivity : AppCompatActivity() { - private val viewModel: SupportViewModel by viewModels() + private val viewModel : SupportViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { + override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { AppTheme { Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background + modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background ) { - SupportComposable(viewModel, this@SupportActivity) + SupportComposable(viewModel , this@SupportActivity) } } } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportComposable.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportComposable.kt index e186ba9..2b39b07 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportComposable.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportComposable.kt @@ -47,68 +47,68 @@ import com.d4rk.cleaner.utils.compose.bounceClick @OptIn(ExperimentalMaterial3Api::class) @Composable -fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { +fun SupportComposable(viewModel : SupportViewModel , activity : SupportActivity) { val context = LocalContext.current val dataStore = DataStore.getInstance(context) - val billingClient = rememberBillingClient(context, viewModel) + val billingClient = rememberBillingClient(context , viewModel) val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) - Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - LargeTopAppBar(title = { Text(stringResource(R.string.support_us)) }, navigationIcon = { + Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = { + LargeTopAppBar(title = { Text(stringResource(R.string.support_us)) } , navigationIcon = { IconButton(onClick = { activity.finish() }) { Icon( - Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null + Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null ) } - }, scrollBehavior = scrollBehavior) + } , scrollBehavior = scrollBehavior) }) { paddingValues -> Box( modifier = Modifier - .padding(paddingValues) - .fillMaxHeight() + .padding(paddingValues) + .fillMaxHeight() ) { LazyColumn { item { Text( - text = stringResource(R.string.paid_support), - modifier = Modifier.padding(start = 16.dp, top = 16.dp), - style = MaterialTheme.typography.titleLarge, + text = stringResource(R.string.paid_support) , + modifier = Modifier.padding(start = 16.dp , top = 16.dp) , + style = MaterialTheme.typography.titleLarge , ) } item { OutlinedCard( modifier = Modifier - .fillMaxWidth() - .padding(16.dp) + .fillMaxWidth() + .padding(16.dp) ) { Column { Text( - text = stringResource(R.string.summary_donations), + text = stringResource(R.string.summary_donations) , modifier = Modifier.padding(16.dp) ) LazyRow( modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), + .fillMaxWidth() + .padding(horizontal = 16.dp) , horizontalArrangement = Arrangement.SpaceEvenly ) { item { FilledTonalButton( modifier = Modifier - .fillMaxWidth() - .bounceClick(), + .fillMaxWidth() + .bounceClick() , onClick = { activity.initiatePurchase( - "low_donation", - viewModel.skuDetails, - billingClient, + "low_donation" , + viewModel.skuDetails , + billingClient , ) - }, + } , ) { Icon( - Icons.Outlined.Paid, - contentDescription = null, + Icons.Outlined.Paid , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing)) @@ -118,19 +118,19 @@ fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { item { FilledTonalButton( modifier = Modifier - .fillMaxWidth() - .bounceClick(), + .fillMaxWidth() + .bounceClick() , onClick = { activity.initiatePurchase( - "normal_donation", - viewModel.skuDetails, - billingClient, + "normal_donation" , + viewModel.skuDetails , + billingClient , ) - }, + } , ) { Icon( - Icons.Outlined.Paid, - contentDescription = null, + Icons.Outlined.Paid , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing)) @@ -140,26 +140,26 @@ fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { } LazyRow( modifier = Modifier - .fillMaxWidth() - .padding(16.dp), + .fillMaxWidth() + .padding(16.dp) , horizontalArrangement = Arrangement.SpaceEvenly ) { item { FilledTonalButton( modifier = Modifier - .fillMaxWidth() - .bounceClick(), + .fillMaxWidth() + .bounceClick() , onClick = { activity.initiatePurchase( - "high_donation", - viewModel.skuDetails, - billingClient, + "high_donation" , + viewModel.skuDetails , + billingClient , ) - }, + } , ) { Icon( - Icons.Outlined.Paid, - contentDescription = null, + Icons.Outlined.Paid , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing)) @@ -170,19 +170,19 @@ fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { FilledTonalButton( modifier = Modifier - .fillMaxWidth() - .bounceClick(), + .fillMaxWidth() + .bounceClick() , onClick = { activity.initiatePurchase( - "extreme_donation", - viewModel.skuDetails, - billingClient, + "extreme_donation" , + viewModel.skuDetails , + billingClient , ) - }, + } , ) { Icon( - Icons.Outlined.Paid, - contentDescription = null, + Icons.Outlined.Paid , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing)) @@ -195,26 +195,26 @@ fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { } item { Text( - text = stringResource(R.string.non_paid_support), - modifier = Modifier.padding(start = 16.dp), - style = MaterialTheme.typography.titleLarge, + text = stringResource(R.string.non_paid_support) , + modifier = Modifier.padding(start = 16.dp) , + style = MaterialTheme.typography.titleLarge , ) } item { FilledTonalButton( onClick = { IntentUtils.openUrl( - context, "https://direct-link.net/548212/agOqI7123501341" + context , "https://direct-link.net/548212/agOqI7123501341" ) - }, + } , modifier = Modifier - .fillMaxWidth() - .bounceClick() - .padding(16.dp), + .fillMaxWidth() + .bounceClick() + .padding(16.dp) , ) { Icon( - Icons.Outlined.Paid, - contentDescription = null, + Icons.Outlined.Paid , + contentDescription = null , modifier = Modifier.size(ButtonDefaults.IconSize) ) Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing)) @@ -223,7 +223,7 @@ fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { } item { LargeBannerAdsComposable( - modifier = Modifier.padding(bottom = 12.dp), dataStore = dataStore + modifier = Modifier.padding(bottom = 12.dp) , dataStore = dataStore ) } } @@ -233,19 +233,15 @@ fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) { @Composable fun rememberBillingClient( - context: Context, - viewModel: SupportViewModel -): BillingClient { + context : Context , viewModel : SupportViewModel +) : BillingClient { val billingClient = remember { - BillingClient.newBuilder(context) - .setListener { _, _ -> } - .enablePendingPurchases() - .build() + BillingClient.newBuilder(context).setListener { _ , _ -> }.enablePendingPurchases().build() } DisposableEffect(billingClient) { billingClient.startConnection(object : BillingClientStateListener { - override fun onBillingSetupFinished(billingResult: BillingResult) { + override fun onBillingSetupFinished(billingResult : BillingResult) { if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) { viewModel.querySkuDetails(billingClient) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportViewModel.kt b/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportViewModel.kt index e2112be..d4d2fc2 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportViewModel.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/ui/support/SupportViewModel.kt @@ -12,20 +12,18 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class SupportViewModel : ViewModel() { - private val _skuDetails = mutableStateMapOf() - val skuDetails: Map = _skuDetails + private val _skuDetails = mutableStateMapOf() + val skuDetails : Map = _skuDetails - fun querySkuDetails(billingClient: BillingClient) { + fun querySkuDetails(billingClient : BillingClient) { viewModelScope.launch(Dispatchers.IO) { val skuList = listOf( - "low_donation", "normal_donation", "high_donation", "extreme_donation" + "low_donation" , "normal_donation" , "high_donation" , "extreme_donation" ) - val params = SkuDetailsParams.newBuilder() - .setSkusList(skuList) - .setType(BillingClient.SkuType.INAPP) - .build() + val params = SkuDetailsParams.newBuilder().setSkusList(skuList) + .setType(BillingClient.SkuType.INAPP).build() - billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList -> + billingClient.querySkuDetailsAsync(params) { billingResult , skuDetailsList -> if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList != null) { skuDetailsList.forEach { skuDetails -> _skuDetails[skuDetails.sku] = skuDetails diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/PermissionsUtils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/PermissionsUtils.kt index 19e08e0..9215f74 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/PermissionsUtils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/PermissionsUtils.kt @@ -25,52 +25,47 @@ object PermissionsUtils { * @param context The application context. * @return True if all required permissions are granted, false otherwise. */ - fun hasStoragePermissions(context: Context): Boolean { + fun hasStoragePermissions(context : Context) : Boolean { val hasStoragePermissions = when { - Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q -> - ContextCompat.checkSelfPermission( - context, - Manifest.permission.WRITE_EXTERNAL_STORAGE - ) == PackageManager.PERMISSION_GRANTED - - Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2 -> - ContextCompat.checkSelfPermission( - context, - Manifest.permission.READ_EXTERNAL_STORAGE - ) == PackageManager.PERMISSION_GRANTED + Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q -> ContextCompat.checkSelfPermission( + context , Manifest.permission.WRITE_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED + + Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2 -> ContextCompat.checkSelfPermission( + context , Manifest.permission.READ_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED else -> true } val hasManageStoragePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { Environment.isExternalStorageManager() - } else { + } + else { true } val hasUsageStatsPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { isAccessGranted(context) - } else { + } + else { true } val hasMediaPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ContextCompat.checkSelfPermission( - context, - Manifest.permission.READ_MEDIA_AUDIO + context , Manifest.permission.READ_MEDIA_AUDIO ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission( - context, - Manifest.permission.READ_MEDIA_IMAGES + context , Manifest.permission.READ_MEDIA_IMAGES ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission( - context, - Manifest.permission.READ_MEDIA_VIDEO + context , Manifest.permission.READ_MEDIA_VIDEO ) == PackageManager.PERMISSION_GRANTED - } else { + } + else { true } - return hasStoragePermissions && hasManageStoragePermission && - hasUsageStatsPermission && hasMediaPermissions + return hasStoragePermissions && hasManageStoragePermission && hasUsageStatsPermission && hasMediaPermissions } @@ -79,21 +74,20 @@ object PermissionsUtils { * * @param activity The Activity instance required to request permissions. */ - fun requestStoragePermissions(activity: Activity) { + fun requestStoragePermissions(activity : Activity) { val requiredPermissions = mutableListOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE + Manifest.permission.WRITE_EXTERNAL_STORAGE , Manifest.permission.READ_EXTERNAL_STORAGE ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - if (!Environment.isExternalStorageManager()) { + if (! Environment.isExternalStorageManager()) { val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) - val uri = Uri.fromParts("package", activity.packageName, null) + val uri = Uri.fromParts("package" , activity.packageName , null) intent.data = uri activity.startActivity(intent) } - if (!isAccessGranted(activity)) { + if (! isAccessGranted(activity)) { val intent = Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS) activity.startActivity(intent) } @@ -102,16 +96,16 @@ object PermissionsUtils { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requiredPermissions.addAll( listOf( - Manifest.permission.READ_MEDIA_AUDIO, - Manifest.permission.READ_MEDIA_IMAGES, + Manifest.permission.READ_MEDIA_AUDIO , + Manifest.permission.READ_MEDIA_IMAGES , Manifest.permission.READ_MEDIA_VIDEO ) ) } ActivityCompat.requestPermissions( - activity, - requiredPermissions.toTypedArray(), + activity , + requiredPermissions.toTypedArray() , PermissionsConstants.REQUEST_CODE_STORAGE_PERMISSIONS ) } @@ -122,17 +116,15 @@ object PermissionsUtils { * @param context The application context. * @return True if access is granted, false otherwise. */ - private fun isAccessGranted(context: Context): Boolean = try { + private fun isAccessGranted(context : Context) : Boolean = try { val packageManager = context.packageManager - val applicationInfo = packageManager.getApplicationInfo(context.packageName, 0) + val applicationInfo = packageManager.getApplicationInfo(context.packageName , 0) val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager - @Suppress("DEPRECATION") val mode: Int = appOpsManager.checkOpNoThrow( - AppOpsManager.OPSTR_GET_USAGE_STATS, - applicationInfo.uid, - applicationInfo.packageName + @Suppress("DEPRECATION") val mode : Int = appOpsManager.checkOpNoThrow( + AppOpsManager.OPSTR_GET_USAGE_STATS , applicationInfo.uid , applicationInfo.packageName ) mode == AppOpsManager.MODE_ALLOWED - } catch (e: PackageManager.NameNotFoundException) { + } catch (e : PackageManager.NameNotFoundException) { false } @@ -143,13 +135,13 @@ object PermissionsUtils { * @param context The application context. * @return True if the permission is granted, false otherwise. */ - fun hasNotificationPermission(context: Context): Boolean { + fun hasNotificationPermission(context : Context) : Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ContextCompat.checkSelfPermission( - context, - Manifest.permission.POST_NOTIFICATIONS + context , Manifest.permission.POST_NOTIFICATIONS ) == PackageManager.PERMISSION_GRANTED - } else { + } + else { true } } @@ -159,11 +151,11 @@ object PermissionsUtils { * * @param activity The Activity instance required to request the permission. */ - fun requestNotificationPermission(activity: Activity) { + fun requestNotificationPermission(activity : Activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ActivityCompat.requestPermissions( - activity, - arrayOf(Manifest.permission.POST_NOTIFICATIONS), + activity , + arrayOf(Manifest.permission.POST_NOTIFICATIONS) , PermissionsConstants.REQUEST_CODE_NOTIFICATION_PERMISSION ) } diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileScanner.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileScanner.kt index 6aebd2a..9fc7fe7 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileScanner.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileScanner.kt @@ -3,6 +3,7 @@ package com.d4rk.cleaner.utils.cleaning import android.content.res.Resources import android.os.Environment import com.d4rk.cleaner.R +import com.d4rk.cleaner.constants.cleaning.ExtensionsConstants import com.d4rk.cleaner.data.datastore.DataStore import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow @@ -20,10 +21,10 @@ import java.io.File * @property dataStore A DataStore instance used for accessing user preferences. * @property resources A Resources instance used for accessing string arrays that define file types. */ -class FileScanner(private val dataStore: DataStore, private val resources: Resources) { +class FileScanner(private val dataStore : DataStore , private val resources : Resources) { - private var preferences: Map = emptyMap() - private var filteredFiles: List = emptyList() + private var preferences : Map = emptyMap() + private var filteredFiles : List = emptyList() /** * Initiates the file scanning process asynchronously. @@ -43,14 +44,16 @@ class FileScanner(private val dataStore: DataStore, private val resources: Resou * The preferences include whether to filter generic files, archive files, APK files, audio files, video files, and image files. */ private suspend fun loadPreferences() { - preferences = mapOf( - "generic_extensions" to dataStore.genericFilter.first(), - "archive_extensions" to dataStore.deleteArchives.first(), - "apk_extensions" to dataStore.deleteApkFiles.first(), - "image_extensions" to dataStore.deleteImageFiles.first(), - "audio_extensions" to dataStore.deleteAudioFiles.first(), - "video_extensions" to dataStore.deleteVideoFiles.first() - ) + preferences = with(ExtensionsConstants) { + mapOf( + GENERIC_EXTENSIONS to dataStore.genericFilter.first() , + ARCHIVE_EXTENSIONS to dataStore.deleteArchives.first() , + APK_EXTENSIONS to dataStore.deleteApkFiles.first() , + IMAGE_EXTENSIONS to dataStore.deleteImageFiles.first() , + AUDIO_EXTENSIONS to dataStore.deleteAudioFiles.first() , + VIDEO_EXTENSIONS to dataStore.deleteVideoFiles.first() + ) + } } /** @@ -58,7 +61,7 @@ class FileScanner(private val dataStore: DataStore, private val resources: Resou * * @return A list of all files found in the external storage directory. */ - private fun getAllFiles(): List { + private fun getAllFiles() : List { val files = mutableListOf() val stack = ArrayDeque() val root = Environment.getExternalStorageDirectory() @@ -68,7 +71,8 @@ class FileScanner(private val dataStore: DataStore, private val resources: Resou val currentFile = stack.removeFirst() if (currentFile.isDirectory) { currentFile.listFiles()?.forEach { stack.addLast(it) } - } else { + } + else { files.add(currentFile) } } @@ -76,47 +80,46 @@ class FileScanner(private val dataStore: DataStore, private val resources: Resou return files } - private fun filterFiles(allFiles: List): Flow = flow { + private fun filterFiles(allFiles : List) : Flow = flow { allFiles.filter(::shouldFilterFile).forEach { emit(it) } } - private fun shouldFilterFile(file: File): Boolean { - return preferences.any { (key, value) -> - when (key) { - "generic_extensions" -> { - val extensions = - resources.getStringArray(R.array.generic_extensions) - value && extensions.map { it.removePrefix(".") } - .contains(file.extension) - } - - "archive_extensions" -> { - val extensions = - resources.getStringArray(R.array.archive_extensions) - value && extensions.contains(file.extension) + private fun shouldFilterFile(file : File) : Boolean { + return preferences.any { (key , value) -> + with(ExtensionsConstants) { + when (key) { + GENERIC_EXTENSIONS -> { + val extensions = resources.getStringArray(R.array.generic_extensions) + value && extensions.map { it.removePrefix(".") }.contains(file.extension) + } + + ARCHIVE_EXTENSIONS -> { + val extensions = resources.getStringArray(R.array.archive_extensions) + value && extensions.contains(file.extension) + } + + APK_EXTENSIONS -> { + val extensions = resources.getStringArray(R.array.apk_extensions) + value && extensions.contains(file.extension) + } + + AUDIO_EXTENSIONS -> { + val extensions = resources.getStringArray(R.array.audio_extensions) + value && extensions.contains(file.extension) + } + + VIDEO_EXTENSIONS -> { + val extensions = resources.getStringArray(R.array.video_extensions) + value && extensions.contains(file.extension) + } + + IMAGE_EXTENSIONS -> { + val extensions = resources.getStringArray(R.array.image_extensions) + value && extensions.contains(file.extension) + } + + else -> false } - - "apk_extensions" -> { - val extensions = resources.getStringArray(R.array.apk_extensions) - value && extensions.contains(file.extension) - } - - "audio_extensions" -> { - val extensions = resources.getStringArray(R.array.audio_extensions) - value && extensions.contains(file.extension) - } - - "video_extensions" -> { - val extensions = resources.getStringArray(R.array.video_extensions) - value && extensions.contains(file.extension) - } - - "image_extensions" -> { - val extensions = resources.getStringArray(R.array.image_extensions) - value && extensions.contains(file.extension) - } - - else -> false } } } @@ -126,7 +129,7 @@ class FileScanner(private val dataStore: DataStore, private val resources: Resou * * @return A list of files that match the user-defined preferences. */ - fun getFilteredFiles(): List { + fun getFilteredFiles() : List { return filteredFiles } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileUtils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileUtils.kt index 63bc648..4867e76 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileUtils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/FileUtils.kt @@ -12,15 +12,12 @@ object FileUtils { * @param size The file size in bytes. * @return A formatted string representing the file size. */ - fun formatSize(size: Long): String { + fun formatSize(size : Long) : String { if (size <= 0) return "0 B" - val units = arrayOf("B", "KB", "MB", "GB", "TB") + val units = arrayOf("B" , "KB" , "MB" , "GB" , "TB") val digitGroups = (log10(size.toDouble()) / log10(1024.0)).toInt() return String.format( - Locale.US, - "%.2f %s", - size / 1024.0.pow(digitGroups.toDouble()), - units[digitGroups] + Locale.US , "%.2f %s" , size / 1024.0.pow(digitGroups.toDouble()) , units[digitGroups] ) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/ImageUtils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/ImageUtils.kt index 2afd624..17a9211 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/ImageUtils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/cleaning/ImageUtils.kt @@ -13,27 +13,27 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext suspend fun getVideoThumbnail( - videoPath: String, - thumbnailWidth: Int = 64, - thumbnailHeight: Int = 64, -): Bitmap? = withContext(Dispatchers.IO) { + videoPath : String , + thumbnailWidth : Int = 64 , + thumbnailHeight : Int = 64 , +) : Bitmap? = withContext(Dispatchers.IO) { val mediaMetadataRetriever = MediaMetadataRetriever() try { mediaMetadataRetriever.setDataSource(videoPath) val bitmap = mediaMetadataRetriever.getFrameAtTime( - 1000, MediaMetadataRetriever.OPTION_CLOSEST_SYNC + 1000 , MediaMetadataRetriever.OPTION_CLOSEST_SYNC ) bitmap?.let { - Bitmap.createScaledBitmap(it, thumbnailWidth, thumbnailHeight, false) + Bitmap.createScaledBitmap(it , thumbnailWidth , thumbnailHeight , false) } - } catch (e: Exception) { + } catch (e : Exception) { null } finally { mediaMetadataRetriever.release() } } -fun getFileIcon(extension: String, context: Context): Int { +fun getFileIcon(extension : String , context : Context) : Int { val lowercaseExtension = extension.lowercase() val resources = context.resources return when (lowercaseExtension) { @@ -46,16 +46,16 @@ fun getFileIcon(extension: String, context: Context): Int { } } -fun Drawable.toBitmapDrawable(resources: Resources = Resources.getSystem()): BitmapDrawable { +fun Drawable.toBitmapDrawable(resources : Resources = Resources.getSystem()) : BitmapDrawable { return when (this) { is BitmapDrawable -> this is AdaptiveIconDrawable -> { val bitmap = - Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888) + Bitmap.createBitmap(intrinsicWidth , intrinsicHeight , Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) - setBounds(0, 0, canvas.width, canvas.height) + setBounds(0 , 0 , canvas.width , canvas.height) draw(canvas) - BitmapDrawable(resources, bitmap) + BitmapDrawable(resources , bitmap) } else -> throw IllegalArgumentException("Unsupported drawable type: ${this::class.java.name}") diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/AnimationUtils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/AnimationUtils.kt index 082255e..583f46f 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/AnimationUtils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/AnimationUtils.kt @@ -25,23 +25,23 @@ fun Modifier.bounceClick() = composed { if (buttonState == ButtonState.Pressed) 0.95f else 1f , label = "" ) this - .graphicsLayer { - scaleX = scale - scaleY = scale - } - .clickable(interactionSource = remember { MutableInteractionSource() } , - indication = null , - onClick = { }) - .pointerInput(buttonState) { - awaitPointerEventScope { - buttonState = if (buttonState == ButtonState.Pressed) { - waitForUpOrCancellation() - ButtonState.Idle - } - else { - awaitFirstDown(false) - ButtonState.Pressed + .graphicsLayer { + scaleX = scale + scaleY = scale + } + .clickable(interactionSource = remember { MutableInteractionSource() } , + indication = null , + onClick = { }) + .pointerInput(buttonState) { + awaitPointerEventScope { + buttonState = if (buttonState == ButtonState.Pressed) { + waitForUpOrCancellation() + ButtonState.Idle + } + else { + awaitFirstDown(false) + ButtonState.Pressed + } } } - } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/ProgressBarsComposables.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/ProgressBarsComposables.kt index a344c25..4d1f9af 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/ProgressBarsComposables.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/ProgressBarsComposables.kt @@ -37,53 +37,52 @@ import com.d4rk.cleaner.data.model.ui.memorymanager.StorageInfo */ @Composable fun CircularDeterminateIndicator( - progress: Float, storageUsed: String, storageTotal: String, modifier: Modifier = Modifier + progress : Float , storageUsed : String , storageTotal : String , modifier : Modifier = Modifier ) { val animatedProgress by animateFloatAsState( - targetValue = progress, - animationSpec = tween(durationMillis = 1000, easing = LinearOutSlowInEasing), + targetValue = progress , + animationSpec = tween(durationMillis = 1000 , easing = LinearOutSlowInEasing) , label = "" ) Box( - contentAlignment = Alignment.Center, modifier = modifier.size(240.dp) + contentAlignment = Alignment.Center , modifier = modifier.size(240.dp) ) { CircularProgressIndicator( - progress = { 1f }, - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.primaryContainer, - strokeWidth = 6.dp, + progress = { 1f } , + modifier = Modifier.fillMaxSize() , + color = MaterialTheme.colorScheme.primaryContainer , + strokeWidth = 6.dp , ) CircularProgressIndicator( - progress = { animatedProgress }, + progress = { animatedProgress } , modifier = Modifier - .animateContentSize() - .fillMaxSize(), - color = MaterialTheme.colorScheme.primary, - strokeWidth = 6.dp, - strokeCap = StrokeCap.Round, + .animateContentSize() + .fillMaxSize() , + color = MaterialTheme.colorScheme.primary , + strokeWidth = 6.dp , + strokeCap = StrokeCap.Round , ) Text( - text = stringResource(R.string.storage_used, storageUsed, storageTotal), - textAlign = TextAlign.Center, + text = stringResource(R.string.storage_used , storageUsed , storageTotal) , + textAlign = TextAlign.Center , style = MaterialTheme.typography.titleLarge ) } } @Composable -fun StorageProgressBar(storageInfo: StorageInfo) { +fun StorageProgressBar(storageInfo : StorageInfo) { val progress = - (storageInfo.usedStorage.toFloat() / storageInfo.totalStorage.toFloat()).coerceIn( - 0f, - 1f - ) + (storageInfo.usedStorage.toFloat() / storageInfo.totalStorage.toFloat()).coerceIn( + 0f , 1f + ) LinearProgressIndicator( - progress = { progress }, + progress = { progress } , modifier = Modifier - .fillMaxWidth() - .animateContentSize() - .height(8.dp), - color = MaterialTheme.colorScheme.primary, + .fillMaxWidth() + .animateContentSize() + .height(8.dp) , + color = MaterialTheme.colorScheme.primary , ) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/SettingsComposablesUtils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/SettingsComposablesUtils.kt index b3340ea..5c5d56e 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/SettingsComposablesUtils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/compose/components/SettingsComposablesUtils.kt @@ -45,34 +45,34 @@ fun SwitchCardComposable( title : String , switchState : State , onSwitchToggled : (Boolean) -> Unit ) { Card(modifier = Modifier - .fillMaxWidth() - .padding(24.dp) - .clip(RoundedCornerShape(28.dp)) - .clickable { - onSwitchToggled(! switchState.value) - }) { + .fillMaxWidth() + .padding(24.dp) + .clip(RoundedCornerShape(28.dp)) + .clickable { + onSwitchToggled(! switchState.value) + }) { Row( modifier = Modifier - .fillMaxWidth() - .padding(16.dp) , + .fillMaxWidth() + .padding(16.dp) , horizontalArrangement = Arrangement.SpaceBetween , verticalAlignment = Alignment.CenterVertically ) { Text(text = title) Switch(checked = switchState.value , - onCheckedChange = onSwitchToggled , - thumbContent = if (switchState.value) { - { - Icon( - Icons.Filled.Check , - contentDescription = null , - modifier = Modifier.size(SwitchDefaults.IconSize) , - ) - } - } - else { - null - }) + onCheckedChange = onSwitchToggled , + thumbContent = if (switchState.value) { + { + Icon( + Icons.Filled.Check , + contentDescription = null , + modifier = Modifier.size(SwitchDefaults.IconSize) , + ) + } + } + else { + null + }) } } } @@ -116,9 +116,9 @@ fun PreferenceItem( ) { Row( modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .clickable(enabled = enabled , onClick = onClick) , + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .clickable(enabled = enabled , onClick = onClick) , verticalAlignment = Alignment.CenterVertically ) { icon?.let { @@ -169,9 +169,9 @@ fun SwitchPreferenceItem( ) { Row( modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .clickable(onClick = { onCheckedChange(! checked) }) , + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .clickable(onClick = { onCheckedChange(! checked) }) , verticalAlignment = Alignment.CenterVertically ) { icon?.let { @@ -181,8 +181,8 @@ fun SwitchPreferenceItem( } Column( modifier = Modifier - .padding(16.dp) - .weight(1f) + .padding(16.dp) + .weight(1f) ) { Text(text = title , style = MaterialTheme.typography.titleLarge) summary?.let { @@ -224,9 +224,9 @@ fun SwitchPreferenceItemWithDivider( ) { Row( modifier = Modifier - .fillMaxWidth() - .clip(RoundedCornerShape(16.dp)) - .clickable(onClick = onClick) , verticalAlignment = Alignment.CenterVertically + .fillMaxWidth() + .clip(RoundedCornerShape(16.dp)) + .clickable(onClick = onClick) , verticalAlignment = Alignment.CenterVertically ) { icon?.let { Spacer(modifier = Modifier.width(16.dp)) @@ -235,8 +235,8 @@ fun SwitchPreferenceItemWithDivider( } Column( modifier = Modifier - .padding(16.dp) - .weight(1f) + .padding(16.dp) + .weight(1f) ) { Text(text = title , style = MaterialTheme.typography.titleLarge) Text(text = summary , style = MaterialTheme.typography.bodyMedium) @@ -244,8 +244,8 @@ fun SwitchPreferenceItemWithDivider( VerticalDivider( modifier = Modifier - .height(32.dp) - .align(Alignment.CenterVertically) , + .height(32.dp) + .align(Alignment.CenterVertically) , color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f) , thickness = 1.dp ) diff --git a/app/src/main/kotlin/com/d4rk/cleaner/utils/imageoptimizer/ImageOptimizerUtils.kt b/app/src/main/kotlin/com/d4rk/cleaner/utils/imageoptimizer/ImageOptimizerUtils.kt index 7137fdb..6974c81 100644 --- a/app/src/main/kotlin/com/d4rk/cleaner/utils/imageoptimizer/ImageOptimizerUtils.kt +++ b/app/src/main/kotlin/com/d4rk/cleaner/utils/imageoptimizer/ImageOptimizerUtils.kt @@ -2,7 +2,7 @@ package com.d4rk.cleaner.utils.imageoptimizer import com.d4rk.cleaner.data.model.ui.imageoptimizer.CompressionLevel -fun getCompressionLevelFromSliderValue(sliderValue: Float): CompressionLevel { +fun getCompressionLevelFromSliderValue(sliderValue : Float) : CompressionLevel { return when { sliderValue < 33f -> CompressionLevel.LOW sliderValue < 66f -> CompressionLevel.MEDIUM diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 4a80d08..471b482 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -49,6 +49,7 @@ Alte fișiere Optimizator de imagini + Selectați imaginea pe care doriți să o optimizați Alegeți imagine Optimizați imaginea Imaginea a fost salvată la: diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index c3a8ecf..f0e592e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -49,6 +49,7 @@ Diğer Dosyalar Resim optimize edici + Optimize etmek istediğiniz resmi seçin Resim seçin Resmi optimize et Resim şuraya kaydedildi: diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index d9f316f..f65d377 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -49,6 +49,7 @@ 其他檔案 圖片優化器 + 選擇您要優化的圖片 選擇圖片 優化圖片 圖片已儲存到: diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 18b3ad0..8986773 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -49,6 +49,7 @@ Other Files Image optimizer + Select the image you want to optimize Choose image Optimize image Image saved to: diff --git a/app/src/main/res/xml/config_locales.xml b/app/src/main/res/xml/config_locales.xml index d7d1860..25d4294 100644 --- a/app/src/main/res/xml/config_locales.xml +++ b/app/src/main/res/xml/config_locales.xml @@ -15,5 +15,5 @@ - + \ No newline at end of file diff --git a/app/src/test/kotlin/com/d4rk/cleaner/ExampleUnitTest.kt b/app/src/test/kotlin/com/d4rk/cleaner/ExampleUnitTest.kt index fc6385f..3ed11a2 100644 --- a/app/src/test/kotlin/com/d4rk/cleaner/ExampleUnitTest.kt +++ b/app/src/test/kotlin/com/d4rk/cleaner/ExampleUnitTest.kt @@ -11,6 +11,6 @@ import org.junit.Test class ExampleUnitTest { @Test fun addition_isCorrect() { - assertEquals(4, 2 + 2) + assertEquals(4 , 2 + 2) } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6f28681..f012b51 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -73,7 +73,7 @@ androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "composeUi" } -androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } +ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "composeUi" } androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "composeMaterial3" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" } kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }