From 29682928e03790e73edc17470ff124582d2787bc Mon Sep 17 00:00:00 2001 From: F0x1d Date: Sat, 17 Aug 2024 16:16:55 +0300 Subject: [PATCH] [feat]: blacklisting in crash details --- .../logfox/database/entity/DisabledApp.kt | 3 ++ .../src/main/res/drawable/ic_check_circle.xml | 10 +++++ .../ui/fragment/picker/AppsPickerFragment.kt | 2 +- .../picker/compose/AppsPickerScreenContent.kt | 8 ++-- .../viewmodel/AppsPickerResultHandler.kt | 2 +- .../core/repository/DisabledAppsRepository.kt | 8 ++++ .../ui/fragment/CrashDetailsFragment.kt | 37 ++++++++++++++++--- .../viewmodel/CrashDetailsViewModel.kt | 22 +++++++++++ .../viewmodel/list/CrashesViewModel.kt | 2 +- .../src/main/res/menu/crash_details_menu.xml | 6 +++ strings/src/main/res/values-ru/strings.xml | 2 + strings/src/main/res/values/strings.xml | 3 ++ 12 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 core/ui/src/main/res/drawable/ic_check_circle.xml diff --git a/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt index 4198315e..994c0a11 100644 --- a/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt +++ b/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt @@ -35,6 +35,9 @@ interface DisabledAppDao { @Query("SELECT * FROM DisabledApp WHERE package_name = :packageName") suspend fun getByPackageName(packageName: String): DisabledApp? + @Query("SELECT * FROM DisabledApp WHERE package_name = :packageName") + fun getByPackageNameAsFlow(packageName: String): Flow + @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insert(item: DisabledApp) diff --git a/core/ui/src/main/res/drawable/ic_check_circle.xml b/core/ui/src/main/res/drawable/ic_check_circle.xml new file mode 100644 index 00000000..9625d649 --- /dev/null +++ b/core/ui/src/main/res/drawable/ic_check_circle.xml @@ -0,0 +1,10 @@ + + + diff --git a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt index 5a687796..2234fe25 100644 --- a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt +++ b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt @@ -46,7 +46,7 @@ class AppsPickerFragment: BaseComposeViewModelFragment() { state to checkedApps }.map { (state, checkedAppPackageNames) -> state.copy( - topBarTitle = handler.provideTopAppBarTitle(requireContext()), + topBarTitle = handler.providePickerTopAppBarTitle(requireContext()), checkedAppPackageNames = checkedAppPackageNames.toImmutableSet(), multiplySelectionEnabled = handler.supportsMultiplySelection, ) diff --git a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt index be685f33..47ce9044 100644 --- a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt +++ b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt @@ -1,6 +1,7 @@ package com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose import androidx.activity.compose.BackHandler +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -125,6 +126,7 @@ private fun LoadingContent(modifier: Modifier = Modifier) { } } +@OptIn(ExperimentalFoundationApi::class) @Composable private fun AppsContent( items: ImmutableList, @@ -142,7 +144,7 @@ private fun AppsContent( key = { _, item -> item.id }, contentType = { _, item -> item.javaClass }, ) { index, item -> - Column { + Column(modifier = Modifier.animateItemPlacement()) { AppContent( item = item, isChecked = remember(checkedItems) { @@ -166,7 +168,7 @@ private fun AppsContent( } @Composable -private fun AppContent( +internal fun AppContent( item: InstalledApp, isChecked: Boolean, onClick: (InstalledApp) -> Unit, @@ -218,7 +220,7 @@ private fun AppContent( } } -private val MockApps = persistentListOf( +internal val MockApps = persistentListOf( InstalledApp("LogFox", "com.f0x1d.logfox"), InstalledApp("Sense", "com.f0x1d.sense"), ) diff --git a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt index 74735db7..819b36b3 100644 --- a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt +++ b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt @@ -13,7 +13,7 @@ interface AppsPickerResultHandler { val supportsMultiplySelection: Boolean get() = false val checkedAppPackageNames: Flow> get() = flowOf(emptySet()) - fun provideTopAppBarTitle(context: Context) = context.getString(Strings.apps) + fun providePickerTopAppBarTitle(context: Context) = context.getString(Strings.apps) fun onAppChecked(app: InstalledApp, checked: Boolean) = Unit diff --git a/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt index 77b868aa..2bf10270 100644 --- a/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt +++ b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt @@ -8,11 +8,13 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext import javax.inject.Inject interface DisabledAppsRepository : DatabaseProxyRepository { suspend fun isDisabledFor(packageName: String): Boolean + fun disabledForFlow(packageName: String): Flow suspend fun checkApp(packageName: String) suspend fun checkApp(packageName: String, checked: Boolean) @@ -27,6 +29,12 @@ internal class DisabledAppsRepositoryImpl @Inject constructor( database.disabledApps().getByPackageName(packageName) != null } + override fun disabledForFlow(packageName: String): Flow = + database.disabledApps() + .getByPackageNameAsFlow(packageName) + .map { it != null } + .flowOn(ioDispatcher) + override suspend fun checkApp(packageName: String) = checkApp( packageName = packageName, checked = withContext(ioDispatcher) { diff --git a/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt index 3ad3586b..a32dab13 100644 --- a/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt +++ b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt @@ -22,7 +22,9 @@ import com.f0x1d.logfox.feature.crashes.core.controller.notificationChannelId import com.f0x1d.logfox.feature.crashes.databinding.FragmentCrashDetailsBinding import com.f0x1d.logfox.feature.crashes.viewmodel.CrashDetailsViewModel import com.f0x1d.logfox.strings.Strings +import com.f0x1d.logfox.ui.Icons import com.f0x1d.logfox.ui.dialog.showAreYouSureDeleteDialog +import com.f0x1d.logfox.ui.dialog.showAreYouSureDialog import com.f0x1d.logfox.ui.view.loadIcon import com.f0x1d.logfox.ui.view.setClickListenerOn import com.f0x1d.logfox.ui.view.setupBackButtonForNavController @@ -53,10 +55,28 @@ class CrashDetailsFragment: BaseViewModelFragment + toolbar.menu.findItem(R.id.blacklist_item).apply { + if (blacklisted == null) { + isVisible = false + } else { + isVisible = true + setIcon(if (blacklisted) Icons.ic_check_circle else Icons.ic_block) + setTitle(if (blacklisted) Strings.remove_from_blacklist else Strings.add_to_blacklist) + } + } + } } @SuppressLint("InlinedApi") @@ -69,17 +89,24 @@ class CrashDetailsFragment: BaseViewModelFragment + crash?.let { + disabledAppsRepository.disabledForFlow(it.packageName) + } ?: flowOf(null) + } + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = null, + ) + val wrapCrashLogLines get() = appPreferences.wrapCrashLogLines val useSeparateNotificationsChannelsForCrashes get() = appPreferences.useSeparateNotificationsChannelsForCrashes @@ -74,6 +92,10 @@ class CrashDetailsViewModel @Inject constructor( } } + fun changeBlacklist(appCrash: AppCrash) = launchCatching { + disabledAppsRepository.checkApp(appCrash.packageName) + } + fun deleteCrash(appCrash: AppCrash) = launchCatching { crashesRepository.delete(appCrash) } diff --git a/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt index 95869d00..b69152c6 100644 --- a/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt +++ b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt @@ -143,7 +143,7 @@ class CrashesViewModel @Inject constructor( apps.map(DisabledApp::packageName).toSet() } - override fun provideTopAppBarTitle(context: Context): String = + override fun providePickerTopAppBarTitle(context: Context): String = context.getString(Strings.blacklist) override fun onAppChecked(app: InstalledApp, checked: Boolean) { diff --git a/feature/crashes/src/main/res/menu/crash_details_menu.xml b/feature/crashes/src/main/res/menu/crash_details_menu.xml index 4114d9a9..7f49c646 100644 --- a/feature/crashes/src/main/res/menu/crash_details_menu.xml +++ b/feature/crashes/src/main/res/menu/crash_details_menu.xml @@ -14,6 +14,12 @@ android:title="@string/notifications" app:showAsAction="ifRoom" /> + + Открывать вкладку сбоев при запуске Перенос строк в деталях лога Черный список + Добавить в черный список + Убрать из черного списка diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index 19b2c062..8fd1cf6f 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -164,4 +164,7 @@ Open crashes page on startup Wrap log lines in details Blacklist + Add to blacklist + Remove from blacklist + Are you sure want to add this app to blacklist? LogFox does not observe crashes for blacklisted apps