From 5a07a130bdbb71a73dd5ba18428828b88192b519 Mon Sep 17 00:00:00 2001 From: F0x1d Date: Sun, 11 Aug 2024 18:05:07 +0300 Subject: [PATCH 1/9] [feat]: disabling word wrap for log in details --- .../preferences/shared/AppPreferences.kt | 3 +++ .../ui/fragment/CrashDetailsFragment.kt | 7 +++++ .../viewmodel/list/CrashesViewModel.kt | 16 ++++++++++- .../res/layout/fragment_crash_details.xml | 27 ++++++++++++------- .../src/main/res/xml/settings_ui.xml | 7 +++++ strings/src/main/res/values-ru/strings.xml | 1 + strings/src/main/res/values/strings.xml | 1 + 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt b/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt index 23fef81e..fcb7206c 100644 --- a/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt +++ b/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt @@ -85,6 +85,9 @@ class AppPreferences @Inject constructor( var exportLogsInOriginalFormat get() = get("pref_export_logs_in_original_format", true) set(value) { put("pref_export_logs_in_original_format", value) } + var wrapCrashLogLines + get() = get("pref_wrap_crash_log_lines", true) + set(value) { put("pref_wrap_crash_log_lines", value) } var showLogDate get() = get("pref_show_log_date", false) diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt index 91b10b51..35204972 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt @@ -9,6 +9,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import com.f0x1d.logfox.arch.notificationsChannelsAvailable @@ -107,6 +108,12 @@ class CrashDetailsFragment: BaseViewModelFragment + logText.isVisible = wrap + logTextScrollableContainer.isVisible = wrap.not() + } + logText.text = crashLog + logTextScrollable.text = crashLog } } diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt index 6062709c..3adf8768 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt @@ -3,6 +3,7 @@ package com.f0x1d.logfox.feature.crashes.viewmodel.list import android.app.Application import androidx.lifecycle.viewModelScope import com.f0x1d.logfox.arch.di.DefaultDispatcher +import com.f0x1d.logfox.arch.di.IODispatcher import com.f0x1d.logfox.arch.viewmodel.BaseViewModel import com.f0x1d.logfox.database.entity.AppCrash import com.f0x1d.logfox.database.entity.AppCrashesCount @@ -11,6 +12,7 @@ import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.preferences.shared.crashes.CrashesSort import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine @@ -20,6 +22,7 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update +import kotlinx.coroutines.withContext import javax.inject.Inject @HiltViewModel @@ -27,6 +30,7 @@ class CrashesViewModel @Inject constructor( private val crashesRepository: CrashesRepository, private val appPreferences: AppPreferences, @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher, + @IODispatcher private val ioDispatcher: CoroutineDispatcher, application: Application, ): BaseViewModel(application) { @@ -70,17 +74,23 @@ class CrashesViewModel @Inject constructor( val query = MutableStateFlow("") + @OptIn(FlowPreview::class) val searchedCrashes = combine( crashesRepository.getAllAsFlow(), query, ) { crashes, query -> crashes to query }.debounce( - timeoutMillis = 100, + timeoutMillis = SEARCH_DEBOUNCE_MILLIS, ).map { (crashes, query) -> crashes.filter { crash -> + val fileContentSettles = withContext(ioDispatcher) { + crash.logDumpFile?.readText()?.contains(query, ignoreCase = false) == true + } + crash.packageName.contains(query, ignoreCase = true) || crash.appName?.contains(query, ignoreCase = true) == true + || fileContentSettles }.map { AppCrashesCount(it) } }.flowOn( defaultDispatcher, @@ -114,4 +124,8 @@ class CrashesViewModel @Inject constructor( val sortType: CrashesSort, val sortInReversedOrder: Boolean, ) + + companion object { + private const val SEARCH_DEBOUNCE_MILLIS = 500L + } } diff --git a/feature/feature-crashes/src/main/res/layout/fragment_crash_details.xml b/feature/feature-crashes/src/main/res/layout/fragment_crash_details.xml index 297cd88c..a8c77581 100644 --- a/feature/feature-crashes/src/main/res/layout/fragment_crash_details.xml +++ b/feature/feature-crashes/src/main/res/layout/fragment_crash_details.xml @@ -140,22 +140,29 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/actions_card"> - + + + android:layout_height="match_parent" + android:scrollbars="none"> - + diff --git a/feature/feature-settings/src/main/res/xml/settings_ui.xml b/feature/feature-settings/src/main/res/xml/settings_ui.xml index 1dabdbcc..81f1a8dd 100644 --- a/feature/feature-settings/src/main/res/xml/settings_ui.xml +++ b/feature/feature-settings/src/main/res/xml/settings_ui.xml @@ -47,6 +47,13 @@ app:singleLineTitle="false" app:widgetLayout="@layout/preference_material_switch" app:iconSpaceReserved="false" /> + По количеству сбоев Использовать разные каналы уведомлений для уведомлений о сбоях Открывать вкладку сбоев при запуске + Перенос строк в деталях лога diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index 860244b1..9bcf3a15 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -162,4 +162,5 @@ By crashes count Use separate notifications channels for crashes notifications Open crashes page on startup + Wrap log lines in details From 17a525fa3c07c6d8b9a09b5ddfb425bd19cff9b9 Mon Sep 17 00:00:00 2001 From: F0x1d Date: Wed, 14 Aug 2024 00:36:23 +0300 Subject: [PATCH 2/9] [feat]: search in crash logs + small refactor --- .../main/kotlin/com/f0x1d/logfox/LogFoxApp.kt | 6 +- ...MainActivityPendingIntentProviderModule.kt | 2 +- .../settings/LoggingServiceDelegateModule.kt | 2 +- .../com/f0x1d/logfox/receiver/BootReceiver.kt | 4 +- .../f0x1d/logfox/ui/activity/MainActivity.kt | 13 ++-- .../f0x1d/logfox/viewmodel/MainViewModel.kt | 11 ++- .../main/kotlin/extensions/Dependencies.kt | 3 - .../src/main/AndroidManifest.xml | 2 +- .../com/f0x1d/logfox/arch}/ContextExt.kt | 3 +- .../kotlin/com/f0x1d/logfox/arch}/FileExt.kt | 2 +- .../com/f0x1d/logfox/arch}/NotificationExt.kt | 2 +- .../com/f0x1d/logfox/arch}/PendingIntents.kt | 3 +- .../logfox/arch/coroutines/flow/FlowExt.kt | 8 --- .../f0x1d/logfox/arch}/io/OutputStreamExt.kt | 2 +- .../logfox/arch}/io/ZipOutputStreamExt.kt | 2 +- .../logfox/arch}/receiver/CopyReceiver.kt | 8 +-- .../logfox/arch/ui/activity/BaseActivity.kt | 3 +- .../arch/ui/activity/BaseViewModelActivity.kt | 21 ++---- .../arch/ui/base/SimpleLifecycleOwner.kt | 32 +++++++++ .../logfox/arch/ui/dialog/BaseBottomSheet.kt | 18 +---- .../ui/dialog/BaseViewModelBottomSheet.kt | 9 +-- .../logfox/arch/ui/fragment/BaseFragment.kt | 18 +---- .../arch/ui/fragment/BaseViewModelFragment.kt | 22 ++---- .../fragment/compose/BaseComposeFragment.kt | 18 ++--- .../compose/BaseComposeViewModelFragment.kt | 12 +--- .../logfox/arch/viewmodel/BaseViewModel.kt | 35 ++++----- .../com/f0x1d/logfox/arch/viewmodel/Event.kt | 7 ++ core/core-context/.gitignore | 1 - core/core-context/build.gradle.kts | 10 --- .../logfox/datetime/DateTimeFormatter.kt | 17 +++-- .../datetime/DateTimeFormatterModule.kt | 16 +++++ core/core-intents/.gitignore | 1 - core/core-intents/build.gradle.kts | 9 --- core/core-io/.gitignore | 1 - core/core-io/build.gradle.kts | 9 --- .../f0x1d/logfox/core/tests/ScreenshotTest.kt | 2 +- .../ui/compose/component/button/RichButton.kt | 68 ++++++------------ core/core-ui/build.gradle.kts | 2 +- .../com/f0x1d/logfox/ui/view/PreferenceExt.kt | 2 +- .../com/f0x1d/logfox/model/event/Event.kt | 17 ----- .../f0x1d/logfox/model/event/NoDataEvent.kt | 10 --- .../f0x1d/logfox/model/event/SnackbarEvent.kt | 7 -- .../CrashesNotificationsController.kt | 14 ++-- .../ui/fragment/CrashDetailsFragment.kt | 10 +-- .../ui/fragment/list/CrashesFragment.kt | 2 +- .../viewmodel/CrashDetailsViewModel.kt | 13 ++-- .../viewmodel/list/CrashesViewModel.kt | 50 +++++++------ .../filters/ui/fragment/EditFilterFragment.kt | 18 ++--- .../filters/viewmodel/EditFilterViewModel.kt | 9 ++- .../feature/logging/adapter/LogsAdapter.kt | 12 ++-- .../feature/logging/service/LoggingService.kt | 12 ++-- .../logging/ui/fragment/LogsFragment.kt | 18 +++-- .../logging/viewmodel/LogsViewModel.kt | 23 ++++-- .../RecordingNotificationController.kt | 14 ++-- .../core/repository/RecordingsRepository.kt | 2 +- .../ui/dialog/RecordingBottomSheet.kt | 8 +-- .../ui/fragment/RecordingsFragment.kt | 11 +-- .../viewmodel/RecordingViewModel.kt | 8 +-- .../viewmodel/RecordingsViewModel.kt | 13 ++-- .../fragment/SettingsNotificationsFragment.kt | 4 +- .../ui/fragment/SettingsServiceFragment.kt | 2 +- .../ui/fragment/SettingsUIFragment.kt | 2 +- .../fragment/base/BasePreferenceFragment.kt | 20 +----- .../setup/compose/SetupScreenContent.kt | 27 +++++-- .../feature/setup/viewmodel/SetupViewModel.kt | 6 +- ...tTest.shouldShowDarkSetupScreenContent.png | Bin 39741 -> 40052 bytes ...ntentTest.shouldShowSetupScreenContent.png | Bin 81418 -> 81418 bytes settings.gradle.kts | 3 - 68 files changed, 330 insertions(+), 411 deletions(-) rename core/{core-context => core-arch}/src/main/AndroidManifest.xml (66%) rename core/{core-context/src/main/kotlin/com/f0x1d/logfox/context => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/ContextExt.kt (96%) rename core/{core-context/src/main/kotlin/com/f0x1d/logfox/context => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/FileExt.kt (88%) rename core/{core-context/src/main/kotlin/com/f0x1d/logfox/context => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/NotificationExt.kt (81%) rename core/{core-intents/src/main/kotlin/com/f0x1d/logfox/intents => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/PendingIntents.kt (95%) delete mode 100644 core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/coroutines/flow/FlowExt.kt rename core/{core-io/src/main/kotlin/com/f0x1d/logfox => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/io/OutputStreamExt.kt (87%) rename core/{core-io/src/main/kotlin/com/f0x1d/logfox => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/io/ZipOutputStreamExt.kt (93%) rename core/{core-context/src/main/kotlin/com/f0x1d/logfox/context => core-arch/src/main/kotlin/com/f0x1d/logfox/arch}/receiver/CopyReceiver.kt (79%) create mode 100644 core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt create mode 100644 core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt delete mode 100644 core/core-context/.gitignore delete mode 100644 core/core-context/build.gradle.kts create mode 100644 core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt delete mode 100644 core/core-intents/.gitignore delete mode 100644 core/core-intents/build.gradle.kts delete mode 100644 core/core-io/.gitignore delete mode 100644 core/core-io/build.gradle.kts delete mode 100644 data/src/main/kotlin/com/f0x1d/logfox/model/event/Event.kt delete mode 100644 data/src/main/kotlin/com/f0x1d/logfox/model/event/NoDataEvent.kt delete mode 100644 data/src/main/kotlin/com/f0x1d/logfox/model/event/SnackbarEvent.kt diff --git a/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt b/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt index 1974d041..38fa307c 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt @@ -4,9 +4,9 @@ import android.app.Application import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationManagerCompat -import com.f0x1d.logfox.context.LOGGING_STATUS_CHANNEL_ID -import com.f0x1d.logfox.context.RECORDING_STATUS_CHANNEL_ID -import com.f0x1d.logfox.context.notificationManagerCompat +import com.f0x1d.logfox.arch.LOGGING_STATUS_CHANNEL_ID +import com.f0x1d.logfox.arch.RECORDING_STATUS_CHANNEL_ID +import com.f0x1d.logfox.arch.notificationManagerCompat import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.strings.Strings import com.google.android.material.color.DynamicColors diff --git a/app/src/main/kotlin/com/f0x1d/logfox/di/logs/MainActivityPendingIntentProviderModule.kt b/app/src/main/kotlin/com/f0x1d/logfox/di/logs/MainActivityPendingIntentProviderModule.kt index 36814a00..2fcaa6ce 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/di/logs/MainActivityPendingIntentProviderModule.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/di/logs/MainActivityPendingIntentProviderModule.kt @@ -3,7 +3,7 @@ package com.f0x1d.logfox.di.logs import android.app.PendingIntent import android.content.Context import com.f0x1d.feature.logging.service.MainActivityPendingIntentProvider -import com.f0x1d.logfox.intents.makeActivityPendingIntent +import com.f0x1d.logfox.arch.makeActivityPendingIntent import com.f0x1d.logfox.ui.activity.MainActivity import dagger.Binds import dagger.Module diff --git a/app/src/main/kotlin/com/f0x1d/logfox/di/settings/LoggingServiceDelegateModule.kt b/app/src/main/kotlin/com/f0x1d/logfox/di/settings/LoggingServiceDelegateModule.kt index 49aacd8a..7269f5eb 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/di/settings/LoggingServiceDelegateModule.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/di/settings/LoggingServiceDelegateModule.kt @@ -2,7 +2,7 @@ package com.f0x1d.logfox.di.settings import android.content.Context import com.f0x1d.feature.logging.service.LoggingService -import com.f0x1d.logfox.context.sendService +import com.f0x1d.logfox.arch.sendService import com.f0x1d.logfox.feature.settings.LoggingServiceDelegate import dagger.Binds import dagger.Module diff --git a/app/src/main/kotlin/com/f0x1d/logfox/receiver/BootReceiver.kt b/app/src/main/kotlin/com/f0x1d/logfox/receiver/BootReceiver.kt index bc32455f..c26d6bf2 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/receiver/BootReceiver.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/receiver/BootReceiver.kt @@ -4,9 +4,9 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import com.f0x1d.feature.logging.service.LoggingService +import com.f0x1d.logfox.arch.hasPermissionToReadLogs import com.f0x1d.logfox.arch.startForegroundServiceAvailable -import com.f0x1d.logfox.context.hasPermissionToReadLogs -import com.f0x1d.logfox.context.toast +import com.f0x1d.logfox.arch.toast import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.terminals.ShizukuTerminal diff --git a/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt b/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt index 35c8f993..d2b0496f 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt @@ -21,15 +21,16 @@ import androidx.transition.TransitionManager import com.f0x1d.logfox.R import com.f0x1d.logfox.arch.contrastedNavBarAvailable import com.f0x1d.logfox.arch.gesturesAvailable +import com.f0x1d.logfox.arch.hasNotificationsPermission +import com.f0x1d.logfox.arch.isHorizontalOrientation import com.f0x1d.logfox.arch.ui.activity.BaseViewModelActivity -import com.f0x1d.logfox.context.hasNotificationsPermission -import com.f0x1d.logfox.context.isHorizontalOrientation +import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.databinding.ActivityMainBinding -import com.f0x1d.logfox.model.event.Event import com.f0x1d.logfox.navigation.Directions import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.Icons import com.f0x1d.logfox.viewmodel.MainViewModel +import com.f0x1d.logfox.viewmodel.OpenSetup import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint @@ -125,8 +126,10 @@ class MainActivity: BaseViewModelActivity(), } override fun onEvent(event: Event) { - when (event.type) { - MainViewModel.EVENT_TYPE_SETUP -> navController.navigate(Directions.action_global_setupFragment) + super.onEvent(event) + + when (event) { + is OpenSetup -> navController.navigate(Directions.action_global_setupFragment) } } diff --git a/app/src/main/kotlin/com/f0x1d/logfox/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/f0x1d/logfox/viewmodel/MainViewModel.kt index 8b82e6f4..3640e272 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/viewmodel/MainViewModel.kt @@ -3,9 +3,10 @@ package com.f0x1d.logfox.viewmodel import android.app.Application import android.content.Intent import com.f0x1d.feature.logging.service.LoggingService +import com.f0x1d.logfox.arch.hasPermissionToReadLogs import com.f0x1d.logfox.arch.startForegroundServiceAvailable import com.f0x1d.logfox.arch.viewmodel.BaseViewModel -import com.f0x1d.logfox.context.hasPermissionToReadLogs +import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.preferences.shared.AppPreferences import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -16,10 +17,6 @@ class MainViewModel @Inject constructor( application: Application, ): BaseViewModel(application) { - companion object { - const val EVENT_TYPE_SETUP = "setup" - } - var askedNotificationsPermission get() = appPreferences.askedNotificationsPermission set(value) { appPreferences.askedNotificationsPermission = value } @@ -39,7 +36,9 @@ class MainViewModel @Inject constructor( ctx.startService(it) } } else { - sendEvent(EVENT_TYPE_SETUP) + sendEvent(OpenSetup) } } } + +data object OpenSetup : Event diff --git a/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt b/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt index 1837aef7..967cd219 100644 --- a/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt +++ b/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt @@ -9,11 +9,8 @@ internal fun DependencyHandlerScope.coreDependencies(withCompose: Boolean = true implementation(project(":strings")) implementation(project(":core:core-arch")) - implementation(project(":core:core-context")) implementation(project(":core:core-database")) implementation(project(":core:core-datetime")) - implementation(project(":core:core-intents")) - implementation(project(":core:core-io")) implementation(project(":core:core-navigation")) implementation(project(":core:core-preferences")) implementation(project(":core:core-terminals")) diff --git a/core/core-context/src/main/AndroidManifest.xml b/core/core-arch/src/main/AndroidManifest.xml similarity index 66% rename from core/core-context/src/main/AndroidManifest.xml rename to core/core-arch/src/main/AndroidManifest.xml index acad04f9..f942e427 100644 --- a/core/core-context/src/main/AndroidManifest.xml +++ b/core/core-arch/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ - + diff --git a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/ContextExt.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt similarity index 96% rename from core/core-context/src/main/kotlin/com/f0x1d/logfox/context/ContextExt.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt index f43c9894..384a0ab9 100644 --- a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/ContextExt.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.context +package com.f0x1d.logfox.arch import android.Manifest import android.annotation.SuppressLint @@ -15,7 +15,6 @@ import android.widget.Toast import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import androidx.core.content.getSystemService -import com.f0x1d.logfox.arch.shouldRequestNotificationsPermission import com.f0x1d.logfox.strings.Strings import java.io.File import kotlin.system.exitProcess diff --git a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/FileExt.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt similarity index 88% rename from core/core-context/src/main/kotlin/com/f0x1d/logfox/context/FileExt.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt index 8dea69bf..6e484ce1 100644 --- a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/FileExt.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.context +package com.f0x1d.logfox.arch import android.content.Context import android.net.Uri diff --git a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/NotificationExt.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt similarity index 81% rename from core/core-context/src/main/kotlin/com/f0x1d/logfox/context/NotificationExt.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt index 5ad327b8..9a375494 100644 --- a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/NotificationExt.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.context +package com.f0x1d.logfox.arch const val LOGGING_STATUS_CHANNEL_ID = "logging" const val RECORDING_STATUS_CHANNEL_ID = "recording" diff --git a/core/core-intents/src/main/kotlin/com/f0x1d/logfox/intents/PendingIntents.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt similarity index 95% rename from core/core-intents/src/main/kotlin/com/f0x1d/logfox/intents/PendingIntents.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt index 4fff33cc..a1acfad8 100644 --- a/core/core-intents/src/main/kotlin/com/f0x1d/logfox/intents/PendingIntents.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.intents +package com.f0x1d.logfox.arch import android.app.Activity import android.app.PendingIntent @@ -7,7 +7,6 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Bundle -import com.f0x1d.logfox.arch.mutablePendingIntentAvailable const val CRASH_DETAILS_INTENT_ID = 0 const val COPY_CRASH_INTENT_ID = 1 diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/coroutines/flow/FlowExt.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/coroutines/flow/FlowExt.kt deleted file mode 100644 index b0d9211a..00000000 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/coroutines/flow/FlowExt.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.f0x1d.logfox.arch.coroutines.flow - -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.update - -inline fun MutableStateFlow>.updateList(block: MutableList.() -> Unit) = update { - it.toMutableList().apply(block) -} diff --git a/core/core-io/src/main/kotlin/com/f0x1d/logfox/io/OutputStreamExt.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt similarity index 87% rename from core/core-io/src/main/kotlin/com/f0x1d/logfox/io/OutputStreamExt.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt index bf213848..e5e9a72e 100644 --- a/core/core-io/src/main/kotlin/com/f0x1d/logfox/io/OutputStreamExt.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.io +package com.f0x1d.logfox.arch.io import java.io.OutputStream import java.util.zip.ZipOutputStream diff --git a/core/core-io/src/main/kotlin/com/f0x1d/logfox/io/ZipOutputStreamExt.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt similarity index 93% rename from core/core-io/src/main/kotlin/com/f0x1d/logfox/io/ZipOutputStreamExt.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt index 6a3366a0..48086ea3 100644 --- a/core/core-io/src/main/kotlin/com/f0x1d/logfox/io/ZipOutputStreamExt.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.io +package com.f0x1d.logfox.arch.io import java.io.File import java.util.zip.ZipEntry diff --git a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/receiver/CopyReceiver.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt similarity index 79% rename from core/core-context/src/main/kotlin/com/f0x1d/logfox/context/receiver/CopyReceiver.kt rename to core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt index fd1c5b06..042876f3 100644 --- a/core/core-context/src/main/kotlin/com/f0x1d/logfox/context/receiver/CopyReceiver.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt @@ -1,11 +1,11 @@ -package com.f0x1d.logfox.context.receiver +package com.f0x1d.logfox.arch.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.f0x1d.logfox.context.copyText -import com.f0x1d.logfox.context.notificationManagerCompat -import com.f0x1d.logfox.context.toast +import com.f0x1d.logfox.arch.copyText +import com.f0x1d.logfox.arch.notificationManagerCompat +import com.f0x1d.logfox.arch.toast import com.f0x1d.logfox.strings.Strings class CopyReceiver: BroadcastReceiver() { diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt index 24d057e4..79c1edb2 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.viewbinding.ViewBinding +import com.f0x1d.logfox.arch.ui.base.SimpleLifecycleOwner import com.f0x1d.logfox.arch.ui.enableEdgeToEdge import com.f0x1d.logfox.arch.ui.snackbar import dagger.hilt.EntryPoint @@ -14,7 +15,7 @@ import dev.chrisbanes.insetter.applyInsetter import io.github.inflationx.viewpump.ViewPump import io.github.inflationx.viewpump.ViewPumpContextWrapper -abstract class BaseActivity: AppCompatActivity() { +abstract class BaseActivity: AppCompatActivity(), SimpleLifecycleOwner { protected lateinit var binding: T diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt index 3030473d..4fb01589 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt @@ -3,7 +3,8 @@ package com.f0x1d.logfox.arch.ui.activity import android.os.Bundle import androidx.viewbinding.ViewBinding import com.f0x1d.logfox.arch.viewmodel.BaseViewModel -import com.f0x1d.logfox.model.event.Event +import com.f0x1d.logfox.arch.viewmodel.Event +import com.f0x1d.logfox.arch.viewmodel.ShowSnackbar abstract class BaseViewModelActivity: BaseActivity() { @@ -12,20 +13,12 @@ abstract class BaseViewModelActivity: BaseAc override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - viewModel.eventsData.observe(this) { - if (it.isConsumed) return@observe - - onEvent(it) - } - - viewModel.snackbarEventsData.observe(this) { - if (it.isConsumed) return@observe + viewModel.eventsFlow.collectWithLifecycle(collector = ::onEvent) + } - it.consume()?.also { message -> - snackbar(message) - } + open fun onEvent(event: Event) { + when (event) { + is ShowSnackbar -> snackbar(event.text) } } - - open fun onEvent(event: Event) = Unit } diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt new file mode 100644 index 00000000..78faabd4 --- /dev/null +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt @@ -0,0 +1,32 @@ +package com.f0x1d.logfox.arch.ui.base + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.coroutineScope +import androidx.lifecycle.repeatOnLifecycle +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.launch + +interface SimpleLifecycleOwner { + + val lifecycle: Lifecycle + fun getViewLifecycleOwner(): LifecycleOwner? = null + + fun Flow.collectWithLifecycle( + state: Lifecycle.State = Lifecycle.State.STARTED, + collector: FlowCollector, + ) { + val lifecycle = getViewLifecycleOwner()?.lifecycle ?: lifecycle + + lifecycle.coroutineScope.launch { + lifecycle.repeatOnLifecycle(state) { + collect(collector) + } + } + } +} + +interface SimpleFragmentLifecycleOwner : SimpleLifecycleOwner { + override fun getViewLifecycleOwner(): LifecycleOwner +} diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt index a7a61e0b..0cacad25 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt @@ -6,19 +6,14 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.viewbinding.ViewBinding +import com.f0x1d.logfox.arch.ui.base.SimpleFragmentLifecycleOwner import com.f0x1d.logfox.arch.ui.enableEdgeToEdge import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.launch -abstract class BaseBottomSheet: BottomSheetDialogFragment() { +abstract class BaseBottomSheet: BottomSheetDialogFragment(), SimpleFragmentLifecycleOwner { private var mutableBinding: T? = null protected val binding: T get() = mutableBinding!! @@ -49,15 +44,6 @@ abstract class BaseBottomSheet: BottomSheetDialogFragment() { return dialog } - protected fun Flow.collectWithLifecycle( - state: Lifecycle.State = Lifecycle.State.STARTED, - collector: FlowCollector, - ) = viewLifecycleOwner.lifecycleScope.launch { - viewLifecycleOwner.repeatOnLifecycle(state) { - collect(collector) - } - } - override fun onDestroyView() { super.onDestroyView() mutableBinding = null diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt index 60f2a69c..f260ea79 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt @@ -4,7 +4,7 @@ import android.os.Bundle import android.view.View import androidx.viewbinding.ViewBinding import com.f0x1d.logfox.arch.viewmodel.BaseViewModel -import com.f0x1d.logfox.model.event.Event +import com.f0x1d.logfox.arch.viewmodel.Event abstract class BaseViewModelBottomSheet: BaseBottomSheet() { @@ -12,12 +12,7 @@ abstract class BaseViewModelBottomSheet: Bas override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - - viewModel.eventsData.observe(viewLifecycleOwner) { - if (it.isConsumed) return@observe - - onEvent(it) - } + viewModel.eventsFlow.collectWithLifecycle(collector = ::onEvent) } open fun onEvent(event: Event) = Unit diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt index 35aad80c..b5dd7197 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt @@ -6,17 +6,12 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.viewbinding.ViewBinding +import com.f0x1d.logfox.arch.ui.base.SimpleFragmentLifecycleOwner import com.f0x1d.logfox.arch.ui.snackbar import dev.chrisbanes.insetter.applyInsetter -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.launch -abstract class BaseFragment: Fragment() { +abstract class BaseFragment: Fragment(), SimpleFragmentLifecycleOwner { private var mutableBinding: T? = null protected val binding: T get() = mutableBinding!! @@ -37,15 +32,6 @@ abstract class BaseFragment: Fragment() { binding.onViewCreated(view, savedInstanceState) } - protected fun Flow.collectWithLifecycle( - state: Lifecycle.State = Lifecycle.State.STARTED, - collector: FlowCollector, - ) = viewLifecycleOwner.lifecycleScope.launch { - viewLifecycleOwner.repeatOnLifecycle(state) { - collect(collector) - } - } - override fun onDestroyView() { super.onDestroyView() mutableBinding = null diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt index 305a8308..af4e719c 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt @@ -4,7 +4,8 @@ import android.os.Bundle import android.view.View import androidx.viewbinding.ViewBinding import com.f0x1d.logfox.arch.viewmodel.BaseViewModel -import com.f0x1d.logfox.model.event.Event +import com.f0x1d.logfox.arch.viewmodel.Event +import com.f0x1d.logfox.arch.viewmodel.ShowSnackbar abstract class BaseViewModelFragment: BaseFragment() { @@ -12,21 +13,12 @@ abstract class BaseViewModelFragment: BaseFr override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel.eventsFlow.collectWithLifecycle(collector = ::onEvent) + } - viewModel.eventsData.observe(viewLifecycleOwner) { - if (it.isConsumed) return@observe - - onEvent(it) - } - - viewModel.snackbarEventsData.observe(viewLifecycleOwner) { - if (it.isConsumed) return@observe - - it.consume()?.also { message -> - snackbar(message) - } + open fun onEvent(event: Event) { + when (event) { + is ShowSnackbar -> snackbar(event.text) } } - - open fun onEvent(event: Event) = Unit } diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt index dfd5e9d5..16301ef9 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import com.f0x1d.logfox.arch.databinding.FragmentComposeBinding import com.f0x1d.logfox.arch.ui.fragment.BaseFragment @@ -19,17 +20,16 @@ abstract class BaseComposeFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - - binding.composeView.apply { - consumeWindowInsets = false - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - - setContent { - this@BaseComposeFragment.Content() - } - } + binding.composeView.setup { Content() } } @Composable abstract fun Content() } + +internal fun ComposeView.setup(content: @Composable () -> Unit) { + consumeWindowInsets = false + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + + setContent(content) +} diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt index 28b38bee..c4b9e94a 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt @@ -4,9 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.ViewCompositionStrategy import com.f0x1d.logfox.arch.databinding.FragmentComposeBinding import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment import com.f0x1d.logfox.arch.ui.snackbar @@ -23,15 +21,7 @@ abstract class BaseComposeViewModelFragment : BaseViewModelFr override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - - binding.composeView.apply { - consumeWindowInsets = false - setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) - - setContent { - this@BaseComposeViewModelFragment.Content() - } - } + binding.composeView.setup { Content() } } override fun snackbar(text: String): Snackbar = requireView().snackbar(text).apply { diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt index 7a737a8c..496497b2 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt @@ -3,37 +3,37 @@ package com.f0x1d.logfox.arch.viewmodel import android.app.Application import android.content.Context import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.f0x1d.logfox.model.event.Event -import com.f0x1d.logfox.model.event.NoDataEvent -import com.f0x1d.logfox.model.event.SnackbarEvent import com.f0x1d.logfox.strings.Strings import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.launch import kotlin.coroutines.CoroutineContext -abstract class BaseViewModel(application: Application): AndroidViewModel(application) { +abstract class BaseViewModel( + application: Application, +) : AndroidViewModel(application) { - val ctx: Context get() = getApplication() + private val eventsChannel = Channel(capacity = Channel.BUFFERED) + val eventsFlow = eventsChannel.receiveAsFlow() - val eventsData = MutableLiveData() - val snackbarEventsData = MutableLiveData() + protected val ctx: Context get() = getApplication() - fun launchCatching( + protected fun launchCatching( context: CoroutineContext = Dispatchers.Main, errorBlock: suspend CoroutineScope.() -> Unit = {}, - block: suspend CoroutineScope.() -> Unit + block: suspend CoroutineScope.() -> Unit, ) = viewModelScope.launch(context) { try { coroutineScope { block(this) } } catch (e: Exception) { - if (e is CancellationException) return@launch + if (e is CancellationException) throw e errorBlock(this) @@ -44,16 +44,11 @@ abstract class BaseViewModel(application: Application): AndroidViewModel(applica } protected fun snackbar(id: Int) = snackbar(ctx.getString(id)) + protected fun snackbar(text: String) = sendEvent(ShowSnackbar(text)) - protected fun snackbar(text: String) { - viewModelScope.launch(Dispatchers.Main.immediate) { - snackbarEventsData.value = SnackbarEvent(text) + protected fun sendEvent(event: Event) { + viewModelScope.launch { + eventsChannel.send(event) } } - - protected fun sendEvent(type: String, data: Any) = eventsData.sendEvent(type, data) - protected fun sendEvent(type: String) = eventsData.sendEvent(type) - - private fun MutableLiveData.sendEvent(type: String, data: Any) = postValue(Event(type, data)) - private fun MutableLiveData.sendEvent(type: String) = postValue(NoDataEvent(type)) } diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt new file mode 100644 index 00000000..43890554 --- /dev/null +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt @@ -0,0 +1,7 @@ +package com.f0x1d.logfox.arch.viewmodel + +interface Event + +data class ShowSnackbar( + val text: String, +) : Event diff --git a/core/core-context/.gitignore b/core/core-context/.gitignore deleted file mode 100644 index 567609b1..00000000 --- a/core/core-context/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/core/core-context/build.gradle.kts b/core/core-context/build.gradle.kts deleted file mode 100644 index 3f1d6817..00000000 --- a/core/core-context/build.gradle.kts +++ /dev/null @@ -1,10 +0,0 @@ -plugins { - id("logfox.android.core") - id("logfox.android.hilt") -} - -android.namespace = "com.f0x1d.logfox.context" - -dependencies { - implementation(project(":core:core-arch")) -} diff --git a/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt b/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt index e94802dc..9267e1af 100644 --- a/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt +++ b/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt @@ -8,18 +8,25 @@ import dagger.hilt.android.qualifiers.ApplicationContext import java.util.Locale import javax.inject.Inject -class DateTimeFormatter @Inject constructor( +interface DateTimeFormatter { + fun formatDate(time: Long): String + fun formatTime(time: Long): String + + fun formatForExport(time: Long): String +} + +internal class DateTimeFormatterImpl @Inject constructor( @ApplicationContext private val context: Context, private val appPreferences: AppPreferences, -) { +) : DateTimeFormatter { private val dateFormatter by lazy { createFormatter(appPreferences.dateFormat) } private val timeFormatter by lazy { createFormatter(appPreferences.timeFormat) } - fun formatDate(time: Long): String = tryFormatBy(dateFormatter, time) - fun formatTime(time: Long): String = tryFormatBy(timeFormatter, time) + override fun formatDate(time: Long): String = tryFormatBy(dateFormatter, time) + override fun formatTime(time: Long): String = tryFormatBy(timeFormatter, time) - fun formatForExport(time: Long) = formatDate(time) + override fun formatForExport(time: Long) = formatDate(time) .withReplacedBadSymbolsForFileName + "-" + formatTime(time) .withReplacedBadSymbolsForFileName diff --git a/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt b/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt new file mode 100644 index 00000000..0881f586 --- /dev/null +++ b/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt @@ -0,0 +1,16 @@ +package com.f0x1d.logfox.datetime + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +internal interface DateTimeFormatterModule { + + @Binds + fun bindDateTimeFormatter( + dateTimeFormatterImpl: DateTimeFormatterImpl, + ): DateTimeFormatter +} diff --git a/core/core-intents/.gitignore b/core/core-intents/.gitignore deleted file mode 100644 index 567609b1..00000000 --- a/core/core-intents/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/core/core-intents/build.gradle.kts b/core/core-intents/build.gradle.kts deleted file mode 100644 index ccb4026a..00000000 --- a/core/core-intents/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id("logfox.android.core") -} - -android.namespace = "com.f0x1d.logfox.intents" - -dependencies { - implementation(project(":core:core-arch")) -} diff --git a/core/core-io/.gitignore b/core/core-io/.gitignore deleted file mode 100644 index 567609b1..00000000 --- a/core/core-io/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/ diff --git a/core/core-io/build.gradle.kts b/core/core-io/build.gradle.kts deleted file mode 100644 index 2ea04906..00000000 --- a/core/core-io/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id("logfox.android.core") -} - -android.namespace = "com.f0x1d.logfox.io" - -dependencies { - -} diff --git a/core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt b/core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt index c2438b5a..67e1ecc1 100644 --- a/core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt +++ b/core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt @@ -42,7 +42,7 @@ abstract class ScreenshotTest { whatToCapture: SemanticsNodeInteractionsProvider.() -> SemanticsNodeInteraction = { onRoot() }, content: @Composable () -> Unit, ) { - composeRule.setContent { content() } + composeRule.setContent(content) composeRule.actions() waitForIdle() diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt index 286f1ba1..90bd140f 100644 --- a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt +++ b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt @@ -1,44 +1,26 @@ package com.f0x1d.logfox.ui.compose.component.button -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.Icons +import com.f0x1d.logfox.ui.compose.preview.DayNightPreview import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme @Composable fun RichButton( - @StringRes text: Int, - @DrawableRes icon: Int, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { - RichButton( - modifier = modifier, - text = stringResource(id = text), - painter = painterResource(id = icon), - onClick = onClick, - ) -} - -@Composable -fun RichButton( - text: String, - painter: Painter, + text: @Composable () -> Unit, + icon: @Composable () -> Unit, onClick: () -> Unit, modifier: Modifier = Modifier, ) { @@ -46,38 +28,28 @@ fun RichButton( modifier = modifier, onClick = onClick, ) { - Icon( - painter = painter, - contentDescription = null, - ) + Box(modifier = Modifier.size(24.dp)) { + icon() + } Spacer(modifier = Modifier.width(8.dp)) - Text( - text = text, - style = MaterialTheme.typography.bodyLarge, - fontWeight = FontWeight.Medium, - ) + ProvideTextStyle(value = MaterialTheme.typography.bodyLarge) { + text() + } } } -@Preview +@DayNightPreview @Composable private fun RichButtonAdbPreview() { LogFoxTheme { RichButton( - text = Strings.adb, - icon = Icons.ic_adb, - onClick = { }, - ) - } -} - -@Preview -@Composable -private fun RichButtonRootPreview() { - LogFoxTheme { - RichButton( - text = "Root", - painter = painterResource(id = Icons.ic_square_root), + text = { Text(text = "ADB") }, + icon = { + Icon( + painter = painterResource(id = Icons.ic_adb), + contentDescription = null, + ) + }, onClick = { }, ) } diff --git a/core/core-ui/build.gradle.kts b/core/core-ui/build.gradle.kts index bf1969d3..c766e068 100644 --- a/core/core-ui/build.gradle.kts +++ b/core/core-ui/build.gradle.kts @@ -6,7 +6,7 @@ plugins { android.namespace = "com.f0x1d.logfox.ui" dependencies { - implementation(project(":core:core-context")) + implementation(project(":core:core-arch")) implementation(project(":core:core-preferences")) implementation(libs.insetter) diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt b/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt index 0ec077d9..f69cea29 100644 --- a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt +++ b/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt @@ -3,7 +3,7 @@ package com.f0x1d.logfox.ui.view import android.view.LayoutInflater import android.view.inputmethod.InputMethodManager import androidx.preference.Preference -import com.f0x1d.logfox.context.inputMethodManager +import com.f0x1d.logfox.arch.inputMethodManager import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.databinding.DialogTextBinding import com.google.android.material.dialog.MaterialAlertDialogBuilder diff --git a/data/src/main/kotlin/com/f0x1d/logfox/model/event/Event.kt b/data/src/main/kotlin/com/f0x1d/logfox/model/event/Event.kt deleted file mode 100644 index 09011a54..00000000 --- a/data/src/main/kotlin/com/f0x1d/logfox/model/event/Event.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.f0x1d.logfox.model.event - -open class Event( - open val type: String, - private val data: Any -) { - var isConsumed = false - protected set - - fun consume(): T? { - if (isConsumed) - return null - - isConsumed = true - return data as T - } -} diff --git a/data/src/main/kotlin/com/f0x1d/logfox/model/event/NoDataEvent.kt b/data/src/main/kotlin/com/f0x1d/logfox/model/event/NoDataEvent.kt deleted file mode 100644 index 625003d3..00000000 --- a/data/src/main/kotlin/com/f0x1d/logfox/model/event/NoDataEvent.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.f0x1d.logfox.model.event - -class NoDataEvent(type: String): Event(type, Unit) { - - override val type: String - get() { - isConsumed = true - return super.type - } -} diff --git a/data/src/main/kotlin/com/f0x1d/logfox/model/event/SnackbarEvent.kt b/data/src/main/kotlin/com/f0x1d/logfox/model/event/SnackbarEvent.kt deleted file mode 100644 index d4ea81df..00000000 --- a/data/src/main/kotlin/com/f0x1d/logfox/model/event/SnackbarEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.f0x1d.logfox.model.event - -class SnackbarEvent(text: String): Event(TYPE, text) { - companion object { - const val TYPE = "snackbar" - } -} diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt index f7d58469..bf01a755 100644 --- a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt +++ b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt @@ -9,14 +9,14 @@ import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.os.bundleOf import androidx.navigation.NavDeepLinkBuilder -import com.f0x1d.logfox.context.CRASHES_CHANNEL_GROUP_ID -import com.f0x1d.logfox.context.doIfNotificationsAllowed -import com.f0x1d.logfox.context.notificationManager -import com.f0x1d.logfox.context.notificationManagerCompat -import com.f0x1d.logfox.context.receiver.CopyReceiver +import com.f0x1d.logfox.arch.COPY_CRASH_INTENT_ID +import com.f0x1d.logfox.arch.CRASHES_CHANNEL_GROUP_ID +import com.f0x1d.logfox.arch.doIfNotificationsAllowed +import com.f0x1d.logfox.arch.makeBroadcastPendingIntent +import com.f0x1d.logfox.arch.notificationManager +import com.f0x1d.logfox.arch.notificationManagerCompat +import com.f0x1d.logfox.arch.receiver.CopyReceiver import com.f0x1d.logfox.database.entity.AppCrash -import com.f0x1d.logfox.intents.COPY_CRASH_INTENT_ID -import com.f0x1d.logfox.intents.makeBroadcastPendingIntent import com.f0x1d.logfox.navigation.Directions import com.f0x1d.logfox.navigation.NavGraphs import com.f0x1d.logfox.preferences.shared.AppPreferences diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt index 35204972..3ad3586b 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt @@ -12,10 +12,10 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import com.f0x1d.logfox.arch.copyText import com.f0x1d.logfox.arch.notificationsChannelsAvailable +import com.f0x1d.logfox.arch.shareIntent import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment -import com.f0x1d.logfox.context.copyText -import com.f0x1d.logfox.context.shareIntent import com.f0x1d.logfox.database.entity.AppCrash import com.f0x1d.logfox.feature.crashes.R import com.f0x1d.logfox.feature.crashes.core.controller.notificationChannelId @@ -72,7 +72,7 @@ class CrashDetailsFragment: BaseViewModelFragment + viewModel.wrapCrashLogLines.let { wrap -> logText.isVisible = wrap logTextScrollableContainer.isVisible = wrap.not() } diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt index 83b6b18c..6be1e0cc 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt @@ -11,8 +11,8 @@ import androidx.core.widget.doAfterTextChanged import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager +import com.f0x1d.logfox.arch.isHorizontalOrientation import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment -import com.f0x1d.logfox.context.isHorizontalOrientation import com.f0x1d.logfox.feature.crashes.R import com.f0x1d.logfox.feature.crashes.adapter.CrashesAdapter import com.f0x1d.logfox.feature.crashes.databinding.DialogSortingBinding diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt index e6b34801..2c00aab7 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt @@ -4,13 +4,13 @@ import android.app.Application import android.net.Uri import androidx.lifecycle.viewModelScope import com.f0x1d.logfox.arch.di.IODispatcher +import com.f0x1d.logfox.arch.io.exportToZip +import com.f0x1d.logfox.arch.io.putZipEntry import com.f0x1d.logfox.arch.viewmodel.BaseViewModel import com.f0x1d.logfox.database.entity.AppCrash import com.f0x1d.logfox.datetime.DateTimeFormatter import com.f0x1d.logfox.feature.crashes.core.repository.CrashesRepository import com.f0x1d.logfox.feature.crashes.di.CrashId -import com.f0x1d.logfox.io.exportToZip -import com.f0x1d.logfox.io.putZipEntry import com.f0x1d.logfox.model.deviceData import com.f0x1d.logfox.preferences.shared.AppPreferences import dagger.hilt.android.lifecycle.HiltViewModel @@ -23,12 +23,12 @@ import javax.inject.Inject @HiltViewModel class CrashDetailsViewModel @Inject constructor( @CrashId val crashId: Long, - val dateTimeFormatter: DateTimeFormatter, private val crashesRepository: CrashesRepository, - val appPreferences: AppPreferences, + private val appPreferences: AppPreferences, @IODispatcher private val ioDispatcher: CoroutineDispatcher, + dateTimeFormatter: DateTimeFormatter, application: Application, -): BaseViewModel(application) { +): BaseViewModel(application), DateTimeFormatter by dateTimeFormatter { val crash = crashesRepository.getByIdAsFlow(crashId) .map { @@ -46,6 +46,9 @@ class CrashDetailsViewModel @Inject constructor( initialValue = null, ) + val wrapCrashLogLines get() = appPreferences.wrapCrashLogLines + val useSeparateNotificationsChannelsForCrashes get() = appPreferences.useSeparateNotificationsChannelsForCrashes + fun exportCrashToZip(uri: Uri) = launchCatching(ioDispatcher) { val (appCrash, crashLog) = crash.value ?: return@launchCatching diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt index 3adf8768..3cb043db 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt @@ -12,11 +12,12 @@ import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.preferences.shared.crashes.CrashesSort import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map @@ -74,27 +75,34 @@ class CrashesViewModel @Inject constructor( val query = MutableStateFlow("") - @OptIn(FlowPreview::class) - val searchedCrashes = combine( - crashesRepository.getAllAsFlow(), - query, - ) { crashes, query -> - crashes to query - }.debounce( - timeoutMillis = SEARCH_DEBOUNCE_MILLIS, - ).map { (crashes, query) -> - crashes.filter { crash -> - val fileContentSettles = withContext(ioDispatcher) { - crash.logDumpFile?.readText()?.contains(query, ignoreCase = false) == true + val searchedCrashes = channelFlow { + combine(crashesRepository.getAllAsFlow(), query) { crashes, query -> + crashes to query + }.collectLatest { (crashes, query) -> + + fun AppCrash.suits(query: String): Boolean = + packageName.contains(query, ignoreCase = true) + || appName?.contains(query, ignoreCase = true) == true + + val filteredCrashes = withContext(defaultDispatcher) { + crashes.filter { it.suits(query) }.map { AppCrashesCount(it) } } - crash.packageName.contains(query, ignoreCase = true) - || crash.appName?.contains(query, ignoreCase = true) == true - || fileContentSettles - }.map { AppCrashesCount(it) } - }.flowOn( - defaultDispatcher, - ).stateIn( + send(filteredCrashes) + delay(SEARCH_DEBOUNCE_MILLIS) // Maybe no need to search content for now + + val deeplyFilteredCrashes = withContext(defaultDispatcher) { + crashes.filter { crash -> + val fileContentSettles = withContext(ioDispatcher) { + crash.logFile?.readText()?.contains(query, ignoreCase = true) == true + } + + crash.suits(query) || fileContentSettles + }.map { AppCrashesCount(it) } + } + send(deeplyFilteredCrashes) + } + }.stateIn( scope = viewModelScope, started = SharingStarted.Eagerly, initialValue = emptyList(), diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt index 5be68334..9ffde3ea 100644 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt +++ b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt @@ -9,13 +9,13 @@ import android.widget.EditText import androidx.activity.result.contract.ActivityResultContracts import androidx.core.widget.doAfterTextChanged import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.lifecycle.asLiveData import androidx.navigation.fragment.findNavController import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment +import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.feature.filters.R import com.f0x1d.logfox.feature.filters.databinding.FragmentEditFilterBinding import com.f0x1d.logfox.feature.filters.viewmodel.EditFilterViewModel -import com.f0x1d.logfox.model.event.Event +import com.f0x1d.logfox.feature.filters.viewmodel.UpdatePackageNameText import com.f0x1d.logfox.model.logline.LogLevel import com.f0x1d.logfox.navigation.Directions import com.f0x1d.logfox.strings.Strings @@ -87,11 +87,11 @@ class EditFilterFragment: BaseViewModelFragment - updateIncludingButton(enabled) - } + viewModel.including.collectWithLifecycle { enabled -> + updateIncludingButton(enabled) + } + viewModel.filter.collectWithLifecycle { viewModel.uid.toText(uidText) viewModel.pid.toText(pidText) viewModel.tid.toText(tidText) @@ -117,8 +117,10 @@ class EditFilterFragment: BaseViewModelFragment { + super.onEvent(event) + + when (event) { + is UpdatePackageNameText -> { binding.packageNameText.setText(viewModel.packageName.value) } } diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt index 9246ebb6..6c38fe09 100644 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt +++ b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt @@ -5,6 +5,7 @@ import android.net.Uri import androidx.lifecycle.viewModelScope import com.f0x1d.logfox.arch.di.IODispatcher import com.f0x1d.logfox.arch.viewmodel.BaseViewModel +import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.database.entity.UserFilter import com.f0x1d.logfox.feature.filters.core.repository.FiltersRepository import com.f0x1d.logfox.feature.filters.di.FilterId @@ -31,10 +32,6 @@ class EditFilterViewModel @Inject constructor( application: Application, ): BaseViewModel(application) { - companion object { - const val EVENT_TYPE_UPDATE_PACKAGE_NAME_TEXT = "update_package_name_text" - } - val filter = filtersRepository.getByIdAsFlow(filterId ?: -1L) .distinctUntilChanged() .take(1) // Not to handle changes @@ -102,7 +99,7 @@ class EditFilterViewModel @Inject constructor( fun selectApp(app: InstalledApp) = packageName.update { app.packageName }.also { - sendEvent(EVENT_TYPE_UPDATE_PACKAGE_NAME_TEXT) + sendEvent(UpdatePackageNameText) } private fun List.toEnabledLogLevels() = mapIndexed { index, value -> @@ -112,3 +109,5 @@ class EditFilterViewModel @Inject constructor( null }.filterNotNull() } + +data object UpdatePackageNameText : Event diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt index 2354819d..4c4a68d1 100644 --- a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt +++ b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt @@ -7,10 +7,12 @@ import com.f0x1d.logfox.arch.adapter.BaseListAdapter import com.f0x1d.logfox.feature.logging.databinding.ItemLogBinding import com.f0x1d.logfox.model.diffCallback import com.f0x1d.logfox.model.logline.LogLine -import com.f0x1d.logfox.preferences.shared.AppPreferences +import com.f0x1d.logfox.model.preferences.ShowLogValues class LogsAdapter( - private val appPreferences: AppPreferences, + private val textSizeProvider: () -> Float, + private val logsExpandedProvider: () -> Boolean, + private val logsFormatProvider: () -> ShowLogValues, private val selectedItem: (LogLine, Boolean) -> Unit, private val copyLog: (LogLine) -> Unit ): BaseListAdapter(diffCallback()) { @@ -22,9 +24,9 @@ class LogsAdapter( notifyItemRangeChanged(0, itemCount) } - val textSize get() = appPreferences.logsTextSize.toFloat() - val logsExpanded get() = appPreferences.logsExpanded - val logsFormat get() = appPreferences.showLogValues + val textSize get() = textSizeProvider() + val logsExpanded get() = logsExpandedProvider() + val logsFormat get() = logsFormatProvider() override fun createHolder(layoutInflater: LayoutInflater, parent: ViewGroup) = LogViewHolder( binding = ItemLogBinding.inflate(layoutInflater, parent, false), diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt index 37f3a461..fb0ef88f 100644 --- a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt +++ b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt @@ -7,10 +7,13 @@ import androidx.core.app.NotificationCompat import androidx.core.app.ServiceCompat import androidx.lifecycle.LifecycleService import androidx.lifecycle.lifecycleScope +import com.f0x1d.logfox.arch.EXIT_APP_INTENT_ID +import com.f0x1d.logfox.arch.LOGGING_STATUS_CHANNEL_ID +import com.f0x1d.logfox.arch.OPEN_APP_INTENT_ID +import com.f0x1d.logfox.arch.activityManager import com.f0x1d.logfox.arch.di.DefaultDispatcher -import com.f0x1d.logfox.context.LOGGING_STATUS_CHANNEL_ID -import com.f0x1d.logfox.context.activityManager -import com.f0x1d.logfox.context.toast +import com.f0x1d.logfox.arch.makeServicePendingIntent +import com.f0x1d.logfox.arch.toast import com.f0x1d.logfox.database.entity.UserFilter import com.f0x1d.logfox.feature.crashes.core.controller.CrashesController import com.f0x1d.logfox.feature.filters.core.repository.FiltersRepository @@ -18,9 +21,6 @@ import com.f0x1d.logfox.feature.logging.core.model.suits import com.f0x1d.logfox.feature.logging.core.repository.LoggingRepository import com.f0x1d.logfox.feature.logging.core.store.LoggingStore import com.f0x1d.logfox.feature.recordings.core.controller.RecordingController -import com.f0x1d.logfox.intents.EXIT_APP_INTENT_ID -import com.f0x1d.logfox.intents.OPEN_APP_INTENT_ID -import com.f0x1d.logfox.intents.makeServicePendingIntent import com.f0x1d.logfox.model.exception.TerminalNotSupportedException import com.f0x1d.logfox.model.logline.LogLine import com.f0x1d.logfox.preferences.shared.AppPreferences diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt index c38a9868..b49f0570 100644 --- a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt +++ b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt @@ -14,10 +14,10 @@ import androidx.recyclerview.widget.RecyclerView import com.f0x1d.feature.logging.adapter.LogsAdapter import com.f0x1d.feature.logging.service.LoggingService import com.f0x1d.feature.logging.viewmodel.LogsViewModel +import com.f0x1d.logfox.arch.copyText +import com.f0x1d.logfox.arch.isHorizontalOrientation +import com.f0x1d.logfox.arch.sendService import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment -import com.f0x1d.logfox.context.copyText -import com.f0x1d.logfox.context.isHorizontalOrientation -import com.f0x1d.logfox.context.sendService import com.f0x1d.logfox.feature.logging.R import com.f0x1d.logfox.feature.logging.databinding.FragmentLogsBinding import com.f0x1d.logfox.model.logline.LogLine @@ -40,15 +40,13 @@ class LogsFragment: BaseViewModelFragment() private val adapter by lazy { LogsAdapter( - appPreferences = viewModel.appPreferences, + textSizeProvider = viewModel::logsTextSize, + logsExpandedProvider = viewModel::logsExpanded, + logsFormatProvider = viewModel::logsFormat, selectedItem = viewModel::selectLine, copyLog = { requireContext().copyText( - viewModel.appPreferences.originalOf( - logLine = it, - formatDate = viewModel.dateTimeFormatter::formatDate, - formatTime = viewModel.dateTimeFormatter::formatTime, - ) + text = viewModel.originalOf(it), ) snackbar(Strings.text_copied) }, @@ -120,7 +118,7 @@ class LogsFragment: BaseViewModelFragment() } setClickListenerOn(R.id.export_selected_item) { exportLogsLauncher.launch( - "${viewModel.dateTimeFormatter.formatForExport(System.currentTimeMillis())}.log" + "${viewModel.formatForExport(System.currentTimeMillis())}.log" ) } setClickListenerOn(R.id.clear_item) { diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt index edae13d2..ee39a5ee 100644 --- a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt +++ b/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt @@ -36,12 +36,12 @@ class LogsViewModel @Inject constructor( private val loggingStore: LoggingStore, private val filtersRepository: FiltersRepository, private val recordingsRepository: RecordingsRepository, - val appPreferences: AppPreferences, - val dateTimeFormatter: DateTimeFormatter, + private val appPreferences: AppPreferences, @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher, @IODispatcher private val ioDispatcher: CoroutineDispatcher, + dateTimeFormatter: DateTimeFormatter, application: Application, -): BaseViewModel(application) { +): BaseViewModel(application), DateTimeFormatter by dateTimeFormatter { val query = MutableStateFlow(null) val queryAndFilters = query.combine( @@ -58,8 +58,8 @@ class LogsViewModel @Inject constructor( val selectedItemsContent get() = selectedItems.value.joinToString("\n") { line -> appPreferences.originalOf( logLine = line, - formatDate = dateTimeFormatter::formatDate, - formatTime = dateTimeFormatter::formatTime, + formatDate = ::formatDate, + formatTime = ::formatTime, ) } @@ -106,6 +106,9 @@ class LogsViewModel @Inject constructor( ) val resumeLoggingWithBottomTouch get() = appPreferences.resumeLoggingWithBottomTouch + val logsTextSize get() = appPreferences.logsTextSize.toFloat() + val logsExpanded get() = appPreferences.logsExpanded + val logsFormat get() = appPreferences.showLogValues fun selectLine(logLine: LogLine, selected: Boolean) = selectedItems.updateSet { if (selected) add( @@ -137,8 +140,8 @@ class LogsViewModel @Inject constructor( selectedItems.value.joinToString("\n") { line -> appPreferences.originalOf( logLine = line, - formatDate = dateTimeFormatter::formatDate, - formatTime = dateTimeFormatter::formatTime, + formatDate = ::formatDate, + formatTime = ::formatTime, ) }.encodeToByteArray() ) @@ -155,6 +158,12 @@ class LogsViewModel @Inject constructor( fun pause() = paused.update { true } fun resume() = paused.update { false } + fun originalOf(logLine: LogLine): String = appPreferences.originalOf( + logLine = logLine, + formatDate = ::formatDate, + formatTime = ::formatTime, + ) + private fun MutableStateFlow>.updateSet(block: MutableSet.() -> Unit) = update { it.toMutableSet().apply(block).toSet() } diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt b/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt index 43386840..349a2a2a 100644 --- a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt +++ b/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt @@ -3,14 +3,14 @@ package com.f0x1d.logfox.feature.recordings.core.controller import android.annotation.SuppressLint import android.content.Context import androidx.core.app.NotificationCompat -import com.f0x1d.logfox.context.RECORDING_STATUS_CHANNEL_ID -import com.f0x1d.logfox.context.doIfNotificationsAllowed -import com.f0x1d.logfox.context.notificationManagerCompat +import com.f0x1d.logfox.arch.PAUSE_RECORDING_INTENT_ID +import com.f0x1d.logfox.arch.RECORDING_STATUS_CHANNEL_ID +import com.f0x1d.logfox.arch.RESUME_RECORDING_INTENT_ID +import com.f0x1d.logfox.arch.STOP_RECORDING_INTENT_ID +import com.f0x1d.logfox.arch.doIfNotificationsAllowed +import com.f0x1d.logfox.arch.makeBroadcastPendingIntent +import com.f0x1d.logfox.arch.notificationManagerCompat import com.f0x1d.logfox.feature.recordings.core.receiver.RecordingReceiver -import com.f0x1d.logfox.intents.PAUSE_RECORDING_INTENT_ID -import com.f0x1d.logfox.intents.RESUME_RECORDING_INTENT_ID -import com.f0x1d.logfox.intents.STOP_RECORDING_INTENT_ID -import com.f0x1d.logfox.intents.makeBroadcastPendingIntent import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.Icons import dagger.hilt.android.qualifiers.ApplicationContext diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt b/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt index 3c306076..f084f013 100644 --- a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt +++ b/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt @@ -4,7 +4,7 @@ import android.content.Context import com.f0x1d.logfox.arch.di.IODispatcher import com.f0x1d.logfox.arch.di.MainDispatcher import com.f0x1d.logfox.arch.repository.DatabaseProxyRepository -import com.f0x1d.logfox.context.toast +import com.f0x1d.logfox.arch.toast import com.f0x1d.logfox.database.AppDatabase import com.f0x1d.logfox.database.entity.LogRecording import com.f0x1d.logfox.datetime.DateTimeFormatter diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt b/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt index fda16b00..6528933f 100644 --- a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt +++ b/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt @@ -9,9 +9,9 @@ import androidx.core.os.bundleOf import androidx.core.widget.doAfterTextChanged import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController +import com.f0x1d.logfox.arch.asUri +import com.f0x1d.logfox.arch.shareFileIntent import com.f0x1d.logfox.arch.ui.dialog.BaseViewModelBottomSheet -import com.f0x1d.logfox.context.asUri -import com.f0x1d.logfox.context.shareFileIntent import com.f0x1d.logfox.feature.recordings.databinding.SheetRecordingBinding import com.f0x1d.logfox.feature.recordings.viewmodel.RecordingViewModel import com.f0x1d.logfox.navigation.Directions @@ -57,13 +57,13 @@ class RecordingBottomSheet: BaseViewModelBottomSheet openDetails(event.consume()) + super.onEvent(event) + + when (event) { + is OpenRecording -> openDetails(event.recording) } } diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt b/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt index 17e9cdad..a7ad50c1 100644 --- a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt +++ b/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt @@ -4,12 +4,12 @@ import android.app.Application import android.net.Uri import androidx.lifecycle.viewModelScope import com.f0x1d.logfox.arch.di.IODispatcher +import com.f0x1d.logfox.arch.io.exportToZip +import com.f0x1d.logfox.arch.io.putZipEntry import com.f0x1d.logfox.arch.viewmodel.BaseViewModel import com.f0x1d.logfox.datetime.DateTimeFormatter import com.f0x1d.logfox.feature.recordings.core.repository.RecordingsRepository import com.f0x1d.logfox.feature.recordings.di.RecordingId -import com.f0x1d.logfox.io.exportToZip -import com.f0x1d.logfox.io.putZipEntry import com.f0x1d.logfox.model.deviceData import com.f0x1d.logfox.preferences.shared.AppPreferences import dagger.hilt.android.lifecycle.HiltViewModel @@ -27,12 +27,12 @@ import javax.inject.Inject @HiltViewModel class RecordingViewModel @Inject constructor( @RecordingId val recordingId: Long, - val dateTimeFormatter: DateTimeFormatter, private val recordingsRepository: RecordingsRepository, private val appPreferences: AppPreferences, @IODispatcher private val ioDispatcher: CoroutineDispatcher, + dateTimeFormatter: DateTimeFormatter, application: Application -): BaseViewModel(application) { +): BaseViewModel(application), DateTimeFormatter by dateTimeFormatter { val recording = recordingsRepository.getByIdAsFlow(recordingId) .distinctUntilChanged() diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt b/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt index 47c84fa1..1a40ded8 100644 --- a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt +++ b/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt @@ -2,6 +2,7 @@ package com.f0x1d.logfox.feature.recordings.viewmodel import android.app.Application import com.f0x1d.logfox.arch.viewmodel.BaseViewModel +import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.database.entity.LogRecording import com.f0x1d.logfox.feature.recordings.core.controller.RecordingController import com.f0x1d.logfox.feature.recordings.core.controller.RecordingState @@ -18,10 +19,6 @@ class RecordingsViewModel @Inject constructor( application: Application, ): BaseViewModel(application) { - companion object { - const val EVENT_TYPE_RECORDING_SAVED = "recording_saved" - } - val recordings = recordingsRepository.getAllAsFlow() .distinctUntilChanged() @@ -32,7 +29,7 @@ class RecordingsViewModel @Inject constructor( recordingController.record() else recordingController.end().also { - sendEvent(EVENT_TYPE_RECORDING_SAVED, it ?: return@also) + sendEvent(OpenRecording(it)) } } @@ -50,7 +47,7 @@ class RecordingsViewModel @Inject constructor( fun saveAll() = launchCatching { snackbar(Strings.saving_logs) recordingsRepository.saveAll().also { - sendEvent(EVENT_TYPE_RECORDING_SAVED, it) + sendEvent(OpenRecording(it)) } } @@ -58,3 +55,7 @@ class RecordingsViewModel @Inject constructor( recordingsRepository.delete(logRecording) } } + +data class OpenRecording( + val recording: LogRecording?, +) : Event diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt index fa4113ac..b5f0858b 100644 --- a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt +++ b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt @@ -5,9 +5,9 @@ import android.content.Intent import android.os.Bundle import android.provider.Settings import androidx.preference.Preference +import com.f0x1d.logfox.arch.LOGGING_STATUS_CHANNEL_ID +import com.f0x1d.logfox.arch.hasNotificationsPermission import com.f0x1d.logfox.arch.notificationsChannelsAvailable -import com.f0x1d.logfox.context.LOGGING_STATUS_CHANNEL_ID -import com.f0x1d.logfox.context.hasNotificationsPermission import com.f0x1d.logfox.feature.settings.R import com.f0x1d.logfox.feature.settings.ui.fragment.base.BasePreferenceFragment import com.f0x1d.logfox.strings.Strings diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt index 7bdf49ad..f1c76cd6 100644 --- a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt +++ b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt @@ -5,7 +5,7 @@ import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat import com.f0x1d.logfox.arch.isAtLeastAndroid13 -import com.f0x1d.logfox.context.toast +import com.f0x1d.logfox.arch.toast import com.f0x1d.logfox.feature.settings.LoggingServiceDelegate import com.f0x1d.logfox.feature.settings.R import com.f0x1d.logfox.feature.settings.fillWithStrings diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt index dd7811e5..3fce5e54 100644 --- a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt +++ b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt @@ -4,7 +4,7 @@ import android.os.Bundle import android.text.InputType import androidx.appcompat.app.AppCompatDelegate import androidx.preference.Preference -import com.f0x1d.logfox.context.catchingNotNumber +import com.f0x1d.logfox.arch.catchingNotNumber import com.f0x1d.logfox.feature.settings.R import com.f0x1d.logfox.feature.settings.fillWithStrings import com.f0x1d.logfox.feature.settings.ui.fragment.base.BasePreferenceFragment diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt index ce74728c..c6446c30 100644 --- a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt +++ b/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt @@ -2,21 +2,16 @@ package com.f0x1d.logfox.feature.settings.ui.fragment.base import android.os.Bundle import android.view.View -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import androidx.preference.PreferenceFragmentCompat -import com.f0x1d.logfox.context.isHorizontalOrientation +import com.f0x1d.logfox.arch.isHorizontalOrientation +import com.f0x1d.logfox.arch.ui.base.SimpleFragmentLifecycleOwner import com.f0x1d.logfox.feature.settings.R import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.view.setupBackButtonForNavController import com.google.android.material.appbar.MaterialToolbar import dev.chrisbanes.insetter.applyInsetter -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.FlowCollector -import kotlinx.coroutines.launch -abstract class BasePreferenceFragment: PreferenceFragmentCompat() { +abstract class BasePreferenceFragment: PreferenceFragmentCompat(), SimpleFragmentLifecycleOwner { open val title = Strings.settings open val showBackArrow = false @@ -40,13 +35,4 @@ abstract class BasePreferenceFragment: PreferenceFragmentCompat() { } } } - - protected fun Flow.collectWithLifecycle( - state: Lifecycle.State = Lifecycle.State.STARTED, - collector: FlowCollector, - ) = lifecycleScope.launch { - repeatOnLifecycle(state) { - collect(collector) - } - } } diff --git a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt b/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt index 3128149f..ac731ac0 100644 --- a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt +++ b/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt @@ -48,21 +48,36 @@ internal fun SetupScreenContent( ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { RichButton( - text = Strings.root, - icon = Icons.ic_square_root, + text = { Text(text = stringResource(id = Strings.root)) }, + icon = { + Icon( + painter = painterResource(id = Icons.ic_square_root), + contentDescription = null, + ) + }, onClick = listener.onRootClick, ) RichButton( modifier = Modifier.testTag(SetupAdbButtonTestTag), - text = Strings.adb, - icon = Icons.ic_adb, + text = { Text(text = stringResource(id = Strings.adb)) }, + icon = { + Icon( + painter = painterResource(id = Icons.ic_adb), + contentDescription = null, + ) + }, onClick = listener.onAdbClick, ) RichButton( - text = Strings.shizuku, - icon = Icons.ic_terminal, + text = { Text(text = stringResource(id = Strings.shizuku)) }, + icon = { + Icon( + painter = painterResource(id = Icons.ic_terminal), + contentDescription = null, + ) + }, onClick = listener.onShizukuClick, ) diff --git a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt b/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt index a5a9bd51..bd4d9ace 100644 --- a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt +++ b/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt @@ -2,10 +2,10 @@ package com.f0x1d.logfox.feature.setup.viewmodel import android.Manifest import android.app.Application +import com.f0x1d.logfox.arch.copyText +import com.f0x1d.logfox.arch.hardRestartApp +import com.f0x1d.logfox.arch.hasPermissionToReadLogs import com.f0x1d.logfox.arch.viewmodel.BaseStateViewModel -import com.f0x1d.logfox.context.copyText -import com.f0x1d.logfox.context.hardRestartApp -import com.f0x1d.logfox.context.hasPermissionToReadLogs import com.f0x1d.logfox.feature.setup.ui.fragment.setup.compose.SetupScreenState import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.strings.Strings diff --git a/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png b/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png index e220c4a140cd8acb76d3bb386084310722ddecbd..31261d65054ef3a0c174ab4efde752f902e7fad8 100644 GIT binary patch delta 25060 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

ddn==`&a2R4aLOnC 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 KJJvb`Ui&waG|bBY delta 24775 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 MZJf^4TKnGoH`T|P=l}o! diff --git a/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png b/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png index a003b541b66cdb5836aca25980949e55e527038b..35eaa09c59c4b64cbe24e575d112524474edce32 100644 GIT binary patch delta 24760 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 TiIZC*m8=(vwyLTepQ8T-8xIDG diff --git a/settings.gradle.kts b/settings.gradle.kts index e60413c4..39a97705 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,11 +21,8 @@ include(":data") include(":strings") include(":core:core-arch") -include(":core:core-context") include(":core:core-database") include(":core:core-datetime") -include(":core:core-intents") -include(":core:core-io") include(":core:core-navigation") include(":core:core-preferences") include(":core:core-terminals") From e91293195e2b9e8e0c076a1b61f9525639c039b1 Mon Sep 17 00:00:00 2001 From: F0x1d Date: Wed, 14 Aug 2024 19:48:42 +0300 Subject: [PATCH 3/9] [feat]: moved apps chooser to another module and refactored to compose --- app/build.gradle.kts | 1 + .../main/kotlin/com/f0x1d/logfox/LogFoxApp.kt | 9 +- .../com/f0x1d/logfox/coil/AppIconFetcher.kt | 49 ++++ .../kotlin/com/f0x1d/logfox/di/CoilModule.kt | 27 +++ .../f0x1d/logfox/ui/activity/MainActivity.kt | 2 +- .../AndroidComposeConventionPlugin.kt | 2 + .../arch/ui/base/SimpleLifecycleOwner.kt | 3 +- .../src/main/res/navigation/logs.xml | 10 +- .../component/button/NavigationBackButton.kt | 32 +++ .../ui/compose/component/button/RichButton.kt | 24 +- .../com/f0x1d/logfox/model/InstalledApp.kt | 2 +- feature/feature-apps-picker/.gitignore | 1 + feature/feature-apps-picker/build.gradle.kts | 9 + .../ui/fragment/picker/AppsPickerFragment.kt | 49 ++++ .../picker/compose/AppsPickerScreenContent.kt | 226 ++++++++++++++++++ .../picker/compose/AppsPickerScreenState.kt | 27 +++ .../viewmodel/AppsPickerResultHandler.kt | 23 ++ .../picker/viewmodel/AppsPickerViewModel.kt | 79 ++++++ feature/feature-filters/build.gradle.kts | 1 + .../feature/filters/adapter/AppsAdapter.kt | 19 -- .../filters/ui/fragment/ChooseAppFragment.kt | 110 --------- .../filters/ui/fragment/EditFilterFragment.kt | 2 +- .../filters/ui/viewholder/AppViewHolder.kt | 30 --- .../filters/viewmodel/ChooseAppViewModel.kt | 64 ----- .../filters/viewmodel/EditFilterViewModel.kt | 14 +- .../main/res/layout/fragment_choose_app.xml | 48 ---- .../src/main/res/layout/item_app.xml | 51 ---- .../src/main/res/menu/choose_app_menu.xml | 8 - gradle/libs.versions.toml | 6 + settings.gradle.kts | 37 ++- 30 files changed, 585 insertions(+), 380 deletions(-) create mode 100644 app/src/main/kotlin/com/f0x1d/logfox/coil/AppIconFetcher.kt create mode 100644 app/src/main/kotlin/com/f0x1d/logfox/di/CoilModule.kt create mode 100644 core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt create mode 100644 feature/feature-apps-picker/.gitignore create mode 100644 feature/feature-apps-picker/build.gradle.kts create mode 100644 feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt create mode 100644 feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt create mode 100644 feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt create mode 100644 feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt create mode 100644 feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt delete mode 100644 feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/AppsAdapter.kt delete mode 100644 feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/ChooseAppFragment.kt delete mode 100644 feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/viewholder/AppViewHolder.kt delete mode 100644 feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/ChooseAppViewModel.kt delete mode 100644 feature/feature-filters/src/main/res/layout/fragment_choose_app.xml delete mode 100644 feature/feature-filters/src/main/res/layout/item_app.xml delete mode 100644 feature/feature-filters/src/main/res/menu/choose_app_menu.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7a24e863..5855ef0f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(libs.viewpump) implementation(libs.gson) + implementation(libs.coil) implementation(libs.glide) ksp(libs.glide.compiler) diff --git a/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt b/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt index 38fa307c..2a2b0767 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt @@ -4,6 +4,8 @@ import android.app.Application import androidx.appcompat.app.AppCompatDelegate import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationManagerCompat +import coil.ImageLoader +import coil.ImageLoaderFactory import com.f0x1d.logfox.arch.LOGGING_STATUS_CHANNEL_ID import com.f0x1d.logfox.arch.RECORDING_STATUS_CHANNEL_ID import com.f0x1d.logfox.arch.notificationManagerCompat @@ -14,11 +16,14 @@ import dagger.hilt.android.HiltAndroidApp import javax.inject.Inject @HiltAndroidApp -class LogFoxApp: Application() { +class LogFoxApp: Application(), ImageLoaderFactory { @Inject lateinit var appPreferences: AppPreferences + @Inject + lateinit var imageLoader: ImageLoader + override fun onCreate() { super.onCreate() AppCompatDelegate.setDefaultNightMode(appPreferences.nightTheme) @@ -51,4 +56,6 @@ class LogFoxApp: Application() { ) } } + + override fun newImageLoader(): ImageLoader = imageLoader } diff --git a/app/src/main/kotlin/com/f0x1d/logfox/coil/AppIconFetcher.kt b/app/src/main/kotlin/com/f0x1d/logfox/coil/AppIconFetcher.kt new file mode 100644 index 00000000..d48e3bc3 --- /dev/null +++ b/app/src/main/kotlin/com/f0x1d/logfox/coil/AppIconFetcher.kt @@ -0,0 +1,49 @@ +package com.f0x1d.logfox.coil + +import android.content.Context +import coil.ImageLoader +import coil.decode.DataSource +import coil.fetch.DrawableResult +import coil.fetch.FetchResult +import coil.fetch.Fetcher +import coil.request.Options +import com.f0x1d.logfox.arch.di.IODispatcher +import com.f0x1d.logfox.model.InstalledApp +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import javax.inject.Inject +import javax.inject.Singleton + +class AppIconFetcher( + private val context: Context, + private val app: InstalledApp, + private val ioDispatcher: CoroutineDispatcher, +) : Fetcher { + + override suspend fun fetch(): FetchResult = withContext(ioDispatcher) { + val appDrawable = context.packageManager.getApplicationIcon(app.packageName) + + DrawableResult( + drawable = appDrawable, + isSampled = true, + dataSource = DataSource.DISK, + ) + } + + @Singleton + class Factory @Inject constructor( + @ApplicationContext private val context: Context, + @IODispatcher private val ioDispatcher: CoroutineDispatcher, + ) : Fetcher.Factory { + override fun create( + data: InstalledApp, + options: Options, + imageLoader: ImageLoader, + ): Fetcher = AppIconFetcher( + context = context, + app = data, + ioDispatcher = ioDispatcher, + ) + } +} diff --git a/app/src/main/kotlin/com/f0x1d/logfox/di/CoilModule.kt b/app/src/main/kotlin/com/f0x1d/logfox/di/CoilModule.kt new file mode 100644 index 00000000..4c15bc1f --- /dev/null +++ b/app/src/main/kotlin/com/f0x1d/logfox/di/CoilModule.kt @@ -0,0 +1,27 @@ +package com.f0x1d.logfox.di + +import android.content.Context +import coil.ImageLoader +import com.f0x1d.logfox.coil.AppIconFetcher +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object CoilModule { + + @Provides + @Singleton + fun provideImageLoader( + @ApplicationContext context: Context, + appIconFetcherFactory: AppIconFetcher.Factory, + ): ImageLoader = ImageLoader.Builder(context) + .components { + add(appIconFetcherFactory) + } + .build() +} diff --git a/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt b/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt index d2b0496f..dd5b068c 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt @@ -139,7 +139,7 @@ class MainActivity: BaseViewModelActivity(), Directions.logsExtendedCopyFragment -> false Directions.filtersFragment -> false Directions.editFilterFragment -> false - Directions.chooseAppFragment -> false + Directions.appsPickerFragment -> false Directions.appCrashesFragment -> false Directions.crashDetailsFragment -> false diff --git a/build-logic/convention/src/main/kotlin/additional/AndroidComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/additional/AndroidComposeConventionPlugin.kt index 3d99bb59..c61c9c2b 100644 --- a/build-logic/convention/src/main/kotlin/additional/AndroidComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/additional/AndroidComposeConventionPlugin.kt @@ -5,6 +5,7 @@ import com.android.build.api.dsl.CommonExtension import com.android.build.api.dsl.LibraryExtension import extensions.bundle import extensions.implementation +import extensions.library import extensions.pluginId import org.gradle.api.Plugin import org.gradle.api.Project @@ -24,6 +25,7 @@ class AndroidComposeConventionPlugin : Plugin { } dependencies { + implementation(library("kotlinx-immutable-collections")) implementation(bundle("androidx-compose")) } } diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt index 78faabd4..9259c03f 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt @@ -17,7 +17,8 @@ interface SimpleLifecycleOwner { state: Lifecycle.State = Lifecycle.State.STARTED, collector: FlowCollector, ) { - val lifecycle = getViewLifecycleOwner()?.lifecycle ?: lifecycle + val viewLifecycleOwner = runCatching { getViewLifecycleOwner() }.getOrNull() + val lifecycle = viewLifecycleOwner?.lifecycle ?: lifecycle lifecycle.coroutineScope.launch { lifecycle.repeatOnLifecycle(state) { diff --git a/core/core-navigation/src/main/res/navigation/logs.xml b/core/core-navigation/src/main/res/navigation/logs.xml index a88ee4be..464a692c 100644 --- a/core/core-navigation/src/main/res/navigation/logs.xml +++ b/core/core-navigation/src/main/res/navigation/logs.xml @@ -68,15 +68,15 @@ android:defaultValue="-1L" /> + android:id="@+id/appsPickerFragment" + android:name="com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.AppsPickerFragment" + android:label="AppsPickerFragment" /> diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt new file mode 100644 index 00000000..881d0ccd --- /dev/null +++ b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt @@ -0,0 +1,32 @@ +package com.f0x1d.logfox.ui.compose.component.button + +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import com.f0x1d.logfox.ui.Icons +import com.f0x1d.logfox.ui.compose.preview.DayNightPreview +import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme + +@Composable +fun NavigationBackButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + IconButton( + modifier = modifier, + onClick = onClick, + ) { + Icon( + painter = painterResource(id = Icons.ic_arrow_back), + contentDescription = null, + ) + } +} + +@DayNightPreview +@Composable +private fun Preview() = LogFoxTheme { + NavigationBackButton(onClick = { }) +} diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt index 90bd140f..978aa7f3 100644 --- a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt +++ b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt @@ -40,17 +40,15 @@ fun RichButton( @DayNightPreview @Composable -private fun RichButtonAdbPreview() { - LogFoxTheme { - RichButton( - text = { Text(text = "ADB") }, - icon = { - Icon( - painter = painterResource(id = Icons.ic_adb), - contentDescription = null, - ) - }, - onClick = { }, - ) - } +private fun RichButtonAdbPreview() = LogFoxTheme { + RichButton( + text = { Text(text = "ADB") }, + icon = { + Icon( + painter = painterResource(id = Icons.ic_adb), + contentDescription = null, + ) + }, + onClick = { }, + ) } diff --git a/data/src/main/kotlin/com/f0x1d/logfox/model/InstalledApp.kt b/data/src/main/kotlin/com/f0x1d/logfox/model/InstalledApp.kt index 118278f7..b77e3ea0 100644 --- a/data/src/main/kotlin/com/f0x1d/logfox/model/InstalledApp.kt +++ b/data/src/main/kotlin/com/f0x1d/logfox/model/InstalledApp.kt @@ -1,7 +1,7 @@ package com.f0x1d.logfox.model data class InstalledApp( - val title: CharSequence, + val title: String, val packageName: String, ) : Identifiable { override val id: Any get() = packageName diff --git a/feature/feature-apps-picker/.gitignore b/feature/feature-apps-picker/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/feature/feature-apps-picker/.gitignore @@ -0,0 +1 @@ +/build diff --git a/feature/feature-apps-picker/build.gradle.kts b/feature/feature-apps-picker/build.gradle.kts new file mode 100644 index 00000000..e215e003 --- /dev/null +++ b/feature/feature-apps-picker/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("logfox.android.feature.compose") +} + +android.namespace = "com.f0x1d.logfox.feature.apps.picker" + +dependencies { + implementation(libs.coil.compose) +} diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt new file mode 100644 index 00000000..b78420b6 --- /dev/null +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt @@ -0,0 +1,49 @@ +package com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import com.f0x1d.logfox.arch.ui.fragment.compose.BaseComposeViewModelFragment +import com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose.AppsPickerScreenContent +import com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose.AppsPickerScreenListener +import com.f0x1d.logfox.feature.apps.picker.viewmodel.AppsPickerViewModel +import com.f0x1d.logfox.feature.apps.picker.viewmodel.resultHandler +import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class AppsPickerFragment: BaseComposeViewModelFragment() { + + override val viewModel by viewModels() + + private val resultHandler by resultHandler() + + private val listener by lazy { + AppsPickerScreenListener( + onBackClicked = { + viewModel.performBackAction(findNavController()::popBackStack) + }, + onAppClicked = { + if (resultHandler?.onAppSelected(it) == true) { + findNavController().popBackStack() + } + }, + onSearchActiveChanged = viewModel::changeSearchActive, + onQueryChanged = viewModel::updateQuery, + ) + } + + @Composable + override fun Content() { + LogFoxTheme { + val state by viewModel.uiState.collectAsState() + + AppsPickerScreenContent( + state = state, + listener = listener, + ) + } + } +} diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt new file mode 100644 index 00000000..830796fc --- /dev/null +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt @@ -0,0 +1,226 @@ +package com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose + +import androidx.activity.compose.BackHandler +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.ime +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.union +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SearchBar +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import coil.compose.AsyncImage +import com.f0x1d.logfox.model.InstalledApp +import com.f0x1d.logfox.strings.Strings +import com.f0x1d.logfox.ui.compose.component.button.NavigationBackButton +import com.f0x1d.logfox.ui.compose.preview.DayNightPreview +import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +@Composable +internal fun AppsPickerScreenContent( + state: AppsPickerScreenState = AppsPickerScreenState(), + listener: AppsPickerScreenListener = MockAppsPickerScreenListener, +) { + Scaffold( + topBar = { + AppsSearchBar( + state = state, + listener = listener, + ) + }, + ) { paddingValues -> + if (state.isLoading) { + LoadingContent(modifier = Modifier.padding(paddingValues)) + } else { + AppsContent( + items = state.apps, + listener = listener, + contentPadding = paddingValues, + ) + } + } + + BackHandler( + enabled = state.searchActive, + onBack = listener.onBackClicked, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun AppsSearchBar( + state: AppsPickerScreenState, + listener: AppsPickerScreenListener, + modifier: Modifier = Modifier, +) { + Surface(modifier = modifier) { + val searchBarPadding by animateDpAsState( + targetValue = if (state.searchActive) 0.dp else 10.dp, + label = "Search bar padding", + ) + + SearchBar( + modifier = Modifier + .fillMaxWidth() + .padding(searchBarPadding), + query = state.query, + onQueryChange = listener.onQueryChanged, + onSearch = { /* noop */ }, + active = state.searchActive, + onActiveChange = listener.onSearchActiveChanged, + placeholder = { Text(text = stringResource(id = Strings.apps)) }, + leadingIcon = { NavigationBackButton(onClick = listener.onBackClicked) } + ) { + AppsContent( + items = state.searchedApps, + listener = listener, + contentPadding = WindowInsets.navigationBars + .union(WindowInsets.ime) + .asPaddingValues(), + ) + } + } +} + +@Composable +private fun LoadingContent(modifier: Modifier = Modifier) { + Box( + modifier = modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + CircularProgressIndicator() + } +} + +@Composable +private fun AppsContent( + items: ImmutableList, + listener: AppsPickerScreenListener, + modifier: Modifier = Modifier, + contentPadding: PaddingValues = PaddingValues(), +) { + LazyColumn( + modifier = modifier.fillMaxSize(), + contentPadding = contentPadding, + ) { + itemsIndexed( + items = items, + key = { _, item -> item.id }, + contentType = { _, item -> item.javaClass }, + ) { index, item -> + Column { + AppContent( + item = item, + onClick = listener.onAppClicked, + ) + + if (index != items.lastIndex) { + HorizontalDivider( + modifier = Modifier.padding( + start = 80.dp, + end = 10.dp, + ) + ) + } + } + } + } +} + +@Composable +private fun AppContent( + item: InstalledApp, + onClick: (InstalledApp) -> Unit, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .fillMaxWidth() + .height(85.dp) + .clickable { onClick(item) } + .padding(horizontal = 10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(10.dp), + ) { + AsyncImage( + modifier = Modifier.size(60.dp), + model = item, + contentDescription = null, + ) + + Column( + modifier = Modifier + .weight(1f) + .height(60.dp), + verticalArrangement = Arrangement.SpaceEvenly, + ) { + Text( + text = item.title, + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + + Text( + text = item.packageName, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + } +} + +internal val MockAppsPickerScreenState = AppsPickerScreenState( + apps = persistentListOf( + InstalledApp("LogFox", "com.f0x1d.logfox"), + InstalledApp("Sense", "com.f0x1d.sense") + ), + isLoading = false, +) + +@DayNightPreview +@Composable +private fun AppsPickerScreenContentPreview() = LogFoxTheme { + AppsPickerScreenContent( + state = MockAppsPickerScreenState, + ) +} + +@DayNightPreview +@Composable +private fun AppContentPreview() = LogFoxTheme { + AppContent( + item = MockAppsPickerScreenState.apps.first(), + onClick = { }, + ) +} diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt new file mode 100644 index 00000000..c9a7a236 --- /dev/null +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt @@ -0,0 +1,27 @@ +package com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose + +import com.f0x1d.logfox.model.InstalledApp +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf + +data class AppsPickerScreenState( + val apps: ImmutableList = persistentListOf(), + val searchedApps: ImmutableList = persistentListOf(), + val isLoading: Boolean = true, + val searchActive: Boolean = false, + val query: String = "", +) + +data class AppsPickerScreenListener( + val onBackClicked: () -> Unit, + val onAppClicked: (InstalledApp) -> Unit, + val onSearchActiveChanged: (Boolean) -> Unit, + val onQueryChanged: (String) -> Unit, +) + +internal val MockAppsPickerScreenListener = AppsPickerScreenListener( + onBackClicked = { }, + onAppClicked = { }, + onSearchActiveChanged = { }, + onQueryChanged = { }, +) diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt new file mode 100644 index 00000000..4b68446d --- /dev/null +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt @@ -0,0 +1,23 @@ +package com.f0x1d.logfox.feature.apps.picker.viewmodel + +import android.annotation.SuppressLint +import androidx.fragment.app.Fragment +import androidx.navigation.fragment.findNavController +import com.f0x1d.logfox.model.InstalledApp + +interface AppsPickerResultHandler { + // pass true to close fragment + fun onAppSelected(app: InstalledApp): Boolean +} + +@SuppressLint("RestrictedApi") +internal fun Fragment.resultHandler(): Lazy = lazy { + val backStackEntry = findNavController().previousBackStackEntry + ?: return@lazy null + + val store = backStackEntry.viewModelStore + val availableViewModelKeys = store.keys() + + availableViewModelKeys + .firstNotNullOfOrNull { store[it] as? AppsPickerResultHandler } +} diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt new file mode 100644 index 00000000..52ef43cb --- /dev/null +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt @@ -0,0 +1,79 @@ +package com.f0x1d.logfox.feature.apps.picker.viewmodel + +import android.app.Application +import com.f0x1d.logfox.arch.di.DefaultDispatcher +import com.f0x1d.logfox.arch.viewmodel.BaseStateViewModel +import com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose.AppsPickerScreenState +import com.f0x1d.logfox.model.InstalledApp +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.update +import javax.inject.Inject + +@HiltViewModel +class AppsPickerViewModel @Inject constructor( + @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher, + application: Application, +): BaseStateViewModel( + initialStateProvider = { AppsPickerScreenState() }, + application = application, +) { + + private val query = MutableStateFlow("") + + init { + load() + } + + fun performBackAction(popBackStack: () -> Unit) = state { + if (searchActive) { + copy(searchActive = false) + } else { + popBackStack() + this + } + } + + fun changeSearchActive(active: Boolean) = state { + copy(searchActive = active) + } + + fun updateQuery(text: String) = state { + copy(query = text) + }.also { + query.update { text } + } + + private fun load() = launchCatching(defaultDispatcher) { + val packageManager = ctx.packageManager + + val installedApps = packageManager.getInstalledPackages(0).map { + InstalledApp( + title = it.applicationInfo.loadLabel(packageManager).toString(), + packageName = it.packageName, + ) + }.sortedBy(InstalledApp::title) + + state { + copy( + apps = installedApps.toImmutableList(), + isLoading = false, + ) + } + + query.map { query -> + installedApps.filter { app -> + app.title.contains(query) || app.packageName.contains(query) + } + }.flowOn( + defaultDispatcher, + ).collectLatest { apps -> + state { copy(searchedApps = apps.toImmutableList()) } + } + } +} diff --git a/feature/feature-filters/build.gradle.kts b/feature/feature-filters/build.gradle.kts index c807dbd5..71d40c00 100644 --- a/feature/feature-filters/build.gradle.kts +++ b/feature/feature-filters/build.gradle.kts @@ -6,6 +6,7 @@ android.namespace = "com.f0x1d.logfox.feature.filters" dependencies { implementation(project(":feature:feature-filters-core")) + implementation(project(":feature:feature-apps-picker")) implementation(libs.gson) diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/AppsAdapter.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/AppsAdapter.kt deleted file mode 100644 index 6f7988e4..00000000 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/AppsAdapter.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.f0x1d.logfox.feature.filters.adapter - -import android.view.LayoutInflater -import android.view.ViewGroup -import com.f0x1d.logfox.arch.adapter.BaseListAdapter -import com.f0x1d.logfox.feature.filters.databinding.ItemAppBinding -import com.f0x1d.logfox.feature.filters.ui.viewholder.AppViewHolder -import com.f0x1d.logfox.model.InstalledApp -import com.f0x1d.logfox.model.diffCallback - -class AppsAdapter( - private val click: (InstalledApp) -> Unit -): BaseListAdapter(diffCallback()) { - - override fun createHolder(layoutInflater: LayoutInflater, parent: ViewGroup) = AppViewHolder( - binding = ItemAppBinding.inflate(layoutInflater, parent, false), - click = click, - ) -} diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/ChooseAppFragment.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/ChooseAppFragment.kt deleted file mode 100644 index 19340ec6..00000000 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/ChooseAppFragment.kt +++ /dev/null @@ -1,110 +0,0 @@ -package com.f0x1d.logfox.feature.filters.ui.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.activity.OnBackPressedCallback -import androidx.core.widget.doAfterTextChanged -import androidx.fragment.app.viewModels -import androidx.hilt.navigation.fragment.hiltNavGraphViewModels -import androidx.navigation.fragment.findNavController -import androidx.recyclerview.widget.LinearLayoutManager -import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment -import com.f0x1d.logfox.feature.filters.R -import com.f0x1d.logfox.feature.filters.adapter.AppsAdapter -import com.f0x1d.logfox.feature.filters.databinding.FragmentChooseAppBinding -import com.f0x1d.logfox.feature.filters.viewmodel.ChooseAppViewModel -import com.f0x1d.logfox.feature.filters.viewmodel.EditFilterViewModel -import com.f0x1d.logfox.model.InstalledApp -import com.f0x1d.logfox.navigation.Directions -import com.f0x1d.logfox.ui.density.dpToPx -import com.f0x1d.logfox.ui.view.setClickListenerOn -import com.f0x1d.logfox.ui.view.setupBackButtonForNavController -import com.google.android.material.divider.MaterialDividerItemDecoration -import com.google.android.material.search.SearchView -import dagger.hilt.android.AndroidEntryPoint -import dev.chrisbanes.insetter.applyInsetter - -@AndroidEntryPoint -class ChooseAppFragment: BaseViewModelFragment() { - - override val viewModel by viewModels() - - private val editFilterViewModel by hiltNavGraphViewModels(Directions.editFilterFragment) - - private val onAppClicked: (InstalledApp) -> Unit = { - editFilterViewModel.selectApp(it) - findNavController().popBackStack() - } - private val appsAdapter = AppsAdapter(onAppClicked) - private val searchedAppsAdapter = AppsAdapter(onAppClicked) - - private val closeSearchOnBackPressedCallback = object : OnBackPressedCallback(false) { - override fun handleOnBackPressed() { - binding.searchView.hide() - } - } - - override fun inflateBinding( - inflater: LayoutInflater, - container: ViewGroup?, - ) = FragmentChooseAppBinding.inflate(inflater, container, false) - - override fun FragmentChooseAppBinding.onViewCreated(view: View, savedInstanceState: Bundle?) { - appsRecycler.applyInsetter { - type(navigationBars = true) { - padding(vertical = true) - } - } - - searchBar.apply { - setupBackButtonForNavController() - - menu.setClickListenerOn(R.id.search_item) { - searchView.show() - } - } - - searchView.apply { - editText.doAfterTextChanged { text -> - viewModel.updateQuery(text?.toString().orEmpty()) - } - - addTransitionListener { _, _, newState -> - closeSearchOnBackPressedCallback.isEnabled = newState == SearchView.TransitionState.SHOWN - } - } - - listOf(appsRecycler, searchedAppsRecycler).forEach { - it.apply { - layoutManager = LinearLayoutManager(requireContext()) - - addItemDecoration( - MaterialDividerItemDecoration( - requireContext(), - LinearLayoutManager.VERTICAL, - ).apply { - dividerInsetStart = 80.dpToPx.toInt() - dividerInsetEnd = 10.dpToPx.toInt() - isLastItemDecorated = false - } - ) - } - } - - appsRecycler.adapter = appsAdapter - searchedAppsRecycler.adapter = searchedAppsAdapter - - viewModel.apps.collectWithLifecycle { - appsAdapter.submitList(it) - } - viewModel.searchedApps.collectWithLifecycle { - searchedAppsAdapter.submitList(it) - } - - requireActivity().onBackPressedDispatcher.apply { - addCallback(viewLifecycleOwner, closeSearchOnBackPressedCallback) - } - } -} diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt index 9ffde3ea..3fa577c6 100644 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt +++ b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt @@ -78,7 +78,7 @@ class EditFilterFragment: BaseViewModelFragment Unit -): BaseViewHolder(binding) { - - init { - binding.apply { - root.setOnClickListener { - click(currentItem ?: return@setOnClickListener) - } - } - } - - override fun ItemAppBinding.bindTo(data: InstalledApp) { - icon.loadIcon(data.packageName) - - title.text = data.title - packageNameText.text = data.packageName - } - - override fun ItemAppBinding.recycle() = Glide.with(icon).clear(icon) -} diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/ChooseAppViewModel.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/ChooseAppViewModel.kt deleted file mode 100644 index 8799af2e..00000000 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/ChooseAppViewModel.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.f0x1d.logfox.feature.filters.viewmodel - -import android.app.Application -import androidx.lifecycle.viewModelScope -import com.f0x1d.logfox.arch.di.DefaultDispatcher -import com.f0x1d.logfox.arch.viewmodel.BaseViewModel -import com.f0x1d.logfox.model.InstalledApp -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.flow.update -import javax.inject.Inject - -@HiltViewModel -class ChooseAppViewModel @Inject constructor( - @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher, - application: Application, -): BaseViewModel(application) { - - val apps = MutableStateFlow(emptyList()) - val query = MutableStateFlow("") - - val searchedApps = combine(apps, query) { apps, query -> - apps to query - }.map { - it.first.filter { app -> - app.title.toString().contains(it.second) || app.packageName.contains(it.second) - } - }.flowOn( - defaultDispatcher, - ).stateIn( - scope = viewModelScope, - started = SharingStarted.Eagerly, - initialValue = emptyList(), - ) - - init { - load() - } - - fun updateQuery(text: String) = query.update { text } - - private fun load() = launchCatching(defaultDispatcher) { - val packageManager = ctx.packageManager - - val installedApps = packageManager.getInstalledPackages(0).map { - InstalledApp( - title = it.applicationInfo.loadLabel(packageManager), - packageName = it.packageName, - ) - }.sortedBy { - it.title.toString() - } - - apps.update { - installedApps - } - } -} diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt index 6c38fe09..726de3cd 100644 --- a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt +++ b/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt @@ -7,6 +7,7 @@ import com.f0x1d.logfox.arch.di.IODispatcher import com.f0x1d.logfox.arch.viewmodel.BaseViewModel import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.database.entity.UserFilter +import com.f0x1d.logfox.feature.apps.picker.viewmodel.AppsPickerResultHandler import com.f0x1d.logfox.feature.filters.core.repository.FiltersRepository import com.f0x1d.logfox.feature.filters.di.FilterId import com.f0x1d.logfox.model.InstalledApp @@ -30,7 +31,7 @@ class EditFilterViewModel @Inject constructor( private val gson: Gson, @IODispatcher private val ioDispatcher: CoroutineDispatcher, application: Application, -): BaseViewModel(application) { +): BaseViewModel(application), AppsPickerResultHandler { val filter = filtersRepository.getByIdAsFlow(filterId ?: -1L) .distinctUntilChanged() @@ -96,10 +97,13 @@ class EditFilterViewModel @Inject constructor( enabledLogLevels[which] = filtering } - fun selectApp(app: InstalledApp) = packageName.update { - app.packageName - }.also { - sendEvent(UpdatePackageNameText) + override fun onAppSelected(app: InstalledApp): Boolean { + packageName.update { + app.packageName + }.also { + sendEvent(UpdatePackageNameText) + } + return true } private fun List.toEnabledLogLevels() = mapIndexed { index, value -> diff --git a/feature/feature-filters/src/main/res/layout/fragment_choose_app.xml b/feature/feature-filters/src/main/res/layout/fragment_choose_app.xml deleted file mode 100644 index 446de45c..00000000 --- a/feature/feature-filters/src/main/res/layout/fragment_choose_app.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/feature/feature-filters/src/main/res/layout/item_app.xml b/feature/feature-filters/src/main/res/layout/item_app.xml deleted file mode 100644 index 00db54dd..00000000 --- a/feature/feature-filters/src/main/res/layout/item_app.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/feature/feature-filters/src/main/res/menu/choose_app_menu.xml b/feature/feature-filters/src/main/res/menu/choose_app_menu.xml deleted file mode 100644 index e643fa06..00000000 --- a/feature/feature-filters/src/main/res/menu/choose_app_menu.xml +++ /dev/null @@ -1,8 +0,0 @@ - -

- - \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5b24718f..4dde1c6c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ minSdk = "24" targetSdk = "34" kotlin = "2.0.0" +kotlinx-immutable-collections = "0.3.7" androidGradlePlugin = "8.5.0" ksp = "2.0.0-1.0.22" hilt = "2.49" @@ -27,6 +28,7 @@ shizuku = "13.1.4" viewpump = "2.1.1" material = "1.12.0" glide = "4.16.0" +coil = "2.7.0" gson = "2.10.1" flow-preferences = "1.9.1" timber = "5.0.1" @@ -40,6 +42,7 @@ androidx-test-espresso = "3.6.1" [libraries] +kotlinx-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinx-immutable-collections" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" } androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } @@ -76,6 +79,9 @@ hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } glide-compiler = { module = "com.github.bumptech.glide:ksp", version.ref = "glide" } +coil = { module = "io.coil-kt:coil", version.ref = "coil" } +coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } +coil-test = { module = "io.coil-kt:coil-test", version.ref = "coil" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } flow-preferences = { module = "com.fredporciuncula:flow-preferences", version.ref = "flow-preferences" } timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 39a97705..494ea520 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,28 +15,21 @@ dependencyResolutionManagement { } } -include(":app") +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -include(":data") -include(":strings") +include( + ":app", + ":data", + ":strings", +) -include(":core:core-arch") -include(":core:core-database") -include(":core:core-datetime") -include(":core:core-navigation") -include(":core:core-preferences") -include(":core:core-terminals") -include(":core:core-tests") -include(":core:core-ui") -include(":core:core-ui-compose") +private val modulesDirectories = setOf("core", "feature") +requireNotNull(rootDir.listFiles()).filter { file -> + file.isDirectory && file.name in modulesDirectories +}.forEach { file -> + val modules = requireNotNull(file.listFiles()) -include(":feature:feature-crashes") -include(":feature:feature-crashes-core") -include(":feature:feature-filters") -include(":feature:feature-filters-core") -include(":feature:feature-logging") -include(":feature:feature-logging-core") -include(":feature:feature-recordings") -include(":feature:feature-recordings-core") -include(":feature:feature-settings") -include(":feature:feature-setup") + modules.filter(File::isDirectory).forEach { moduleFile -> + include(":${file.name}:${moduleFile.name}") + } +} From e9a5435124dc05c9e649c9d5bafef29892027de6 Mon Sep 17 00:00:00 2001 From: F0x1d Date: Thu, 15 Aug 2024 00:26:10 +0300 Subject: [PATCH 4/9] [feat]: crashes blacklist --- app/build.gradle.kts | 24 +- .../arch/viewmodel/BaseStateViewModel.kt | 1 + core/core-database/build.gradle.kts | 2 +- .../17.json | 254 ++++++++++++++++++ .../com/f0x1d/logfox/database/AppDatabase.kt | 10 +- .../logfox/database/entity/DisabledApp.kt | 52 ++++ core/core-datetime/build.gradle.kts | 2 +- .../src/main/res/navigation/crashes.xml | 12 + core/core-preferences/build.gradle.kts | 2 +- core/core-terminals/build.gradle.kts | 2 +- core/core-ui-compose/build.gradle.kts | 2 +- .../compose/component/search/TopSearchBar.kt | 65 +++++ core/core-ui/build.gradle.kts | 4 +- .../src/main/res/drawable/ic_block.xml | 12 + .../ui/fragment/picker/AppsPickerFragment.kt | 22 +- .../picker/compose/AppsPickerScreenContent.kt | 134 ++++----- .../picker/compose/AppsPickerScreenState.kt | 6 + .../viewmodel/AppsPickerResultHandler.kt | 9 +- .../picker/viewmodel/AppsPickerViewModel.kt | 3 +- .../core/controller/CrashesController.kt | 42 +-- .../crashes/core/di/RepositoriesModule.kt | 7 + .../core/repository/CrashesRepository.kt | 25 +- .../core/repository/DisabledAppsRepository.kt | 72 +++++ feature/feature-crashes/build.gradle.kts | 4 +- .../ui/fragment/list/CrashesFragment.kt | 7 +- .../viewmodel/list/CrashesViewModel.kt | 29 +- .../src/main/res/menu/crashes_menu.xml | 6 + .../core/repository/FiltersRepository.kt | 4 +- feature/feature-filters/build.gradle.kts | 7 +- feature/feature-logging/build.gradle.kts | 8 +- .../feature-recordings-core/build.gradle.kts | 2 +- .../core/repository/RecordingsRepository.kt | 5 +- feature/feature-recordings/build.gradle.kts | 2 +- strings/src/main/res/values-ru/strings.xml | 1 + strings/src/main/res/values/strings.xml | 1 + 35 files changed, 720 insertions(+), 120 deletions(-) create mode 100644 core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json create mode 100644 core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt create mode 100644 core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt create mode 100644 core/core-ui/src/main/res/drawable/ic_block.xml create mode 100644 feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5855ef0f..56f194da 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -9,22 +9,22 @@ android { defaultConfig { applicationId = logFoxPackageName - versionCode = 61 - versionName = "2.0.1" + versionCode = 62 + versionName = "2.0.2" } } dependencies { - implementation(project(":feature:feature-crashes")) - implementation(project(":feature:feature-crashes-core")) - implementation(project(":feature:feature-filters")) - implementation(project(":feature:feature-filters-core")) - implementation(project(":feature:feature-logging")) - implementation(project(":feature:feature-logging-core")) - implementation(project(":feature:feature-recordings")) - implementation(project(":feature:feature-recordings-core")) - implementation(project(":feature:feature-settings")) - implementation(project(":feature:feature-setup")) + implementation(projects.feature.featureCrashes) + implementation(projects.feature.featureCrashesCore) + implementation(projects.feature.featureFilters) + implementation(projects.feature.featureFiltersCore) + implementation(projects.feature.featureLogging) + implementation(projects.feature.featureLoggingCore) + implementation(projects.feature.featureRecordings) + implementation(projects.feature.featureRecordingsCore) + implementation(projects.feature.featureSettings) + implementation(projects.feature.featureSetup) implementation(libs.insetter) implementation(libs.bundles.shizuku) diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt index f5ed692d..da539adb 100644 --- a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt +++ b/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt @@ -12,6 +12,7 @@ abstract class BaseStateViewModel( private val mutableUiState = MutableStateFlow(initialStateProvider()) val uiState = mutableUiState.asStateFlow() + val currentState: T = uiState.value protected fun state(block: T.() -> T) = mutableUiState.update(block) } diff --git a/core/core-database/build.gradle.kts b/core/core-database/build.gradle.kts index 7b0bd0f3..8cdced3d 100644 --- a/core/core-database/build.gradle.kts +++ b/core/core-database/build.gradle.kts @@ -14,7 +14,7 @@ android { } dependencies { - implementation(project(":core:core-arch")) + implementation(projects.core.coreArch) implementation(libs.androidx.room) implementation(libs.androidx.room.runtime) diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json b/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json new file mode 100644 index 00000000..a510d3e5 --- /dev/null +++ b/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json @@ -0,0 +1,254 @@ +{ + "formatVersion": 1, + "database": { + "version": 17, + "identityHash": "a2c925fa72fa2086ac30fe2fde7ce585", + "entities": [ + { + "tableName": "AppCrash", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`app_name` TEXT, `package_name` TEXT NOT NULL, `crash_type` INTEGER NOT NULL, `date_and_time` INTEGER NOT NULL, `log` TEXT NOT NULL, `log_file` TEXT, `log_dump_file` TEXT, `is_deleted` INTEGER NOT NULL DEFAULT 0, `deleted_time` INTEGER, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "appName", + "columnName": "app_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "packageName", + "columnName": "package_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "crashType", + "columnName": "crash_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateAndTime", + "columnName": "date_and_time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "log", + "columnName": "log", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "logFile", + "columnName": "log_file", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "logDumpFile", + "columnName": "log_dump_file", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDeleted", + "columnName": "is_deleted", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "deletedTime", + "columnName": "deleted_time", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_AppCrash_date_and_time", + "unique": false, + "columnNames": [ + "date_and_time" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_AppCrash_date_and_time` ON `${TABLE_NAME}` (`date_and_time`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "LogRecording", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`title` TEXT NOT NULL, `date_and_time` INTEGER NOT NULL, `file` TEXT NOT NULL, `is_cache_recording` INTEGER NOT NULL DEFAULT 0, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateAndTime", + "columnName": "date_and_time", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "file", + "columnName": "file", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isCacheRecording", + "columnName": "is_cache_recording", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "0" + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "UserFilter", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`including` INTEGER NOT NULL, `allowed_levels` TEXT NOT NULL, `uid` TEXT, `pid` TEXT, `tid` TEXT, `package_name` TEXT, `tag` TEXT, `content` TEXT, `enabled` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "including", + "columnName": "including", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "allowedLevels", + "columnName": "allowed_levels", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "uid", + "columnName": "uid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "pid", + "columnName": "pid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tid", + "columnName": "tid", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "packageName", + "columnName": "package_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "tag", + "columnName": "tag", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "enabled", + "columnName": "enabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "DisabledApp", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)", + "fields": [ + { + "fieldPath": "packageName", + "columnName": "package_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_DisabledApp_package_name", + "unique": false, + "columnNames": [ + "package_name" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_DisabledApp_package_name` ON `${TABLE_NAME}` (`package_name`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a2c925fa72fa2086ac30fe2fde7ce585')" + ] + } +} \ No newline at end of file diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt b/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt index d6e0db5d..7c3aac13 100644 --- a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt +++ b/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt @@ -11,6 +11,8 @@ import com.f0x1d.logfox.database.entity.AllowedLevelsConverter import com.f0x1d.logfox.database.entity.AppCrash import com.f0x1d.logfox.database.entity.AppCrashDao import com.f0x1d.logfox.database.entity.CrashTypeConverter +import com.f0x1d.logfox.database.entity.DisabledApp +import com.f0x1d.logfox.database.entity.DisabledAppDao import com.f0x1d.logfox.database.entity.FileConverter import com.f0x1d.logfox.database.entity.LogRecording import com.f0x1d.logfox.database.entity.LogRecordingDao @@ -22,8 +24,9 @@ import com.f0x1d.logfox.database.entity.UserFilterDao AppCrash::class, LogRecording::class, UserFilter::class, + DisabledApp::class, ], - version = 16, + version = 17, autoMigrations = [ AutoMigration( from = 12, @@ -42,6 +45,10 @@ import com.f0x1d.logfox.database.entity.UserFilterDao from = 15, to = 16, ), + AutoMigration( + from = 16, + to = 17, + ), ] ) @TypeConverters( @@ -92,4 +99,5 @@ abstract class AppDatabase: RoomDatabase() { abstract fun appCrashes(): AppCrashDao abstract fun logRecordings(): LogRecordingDao abstract fun userFilters(): UserFilterDao + abstract fun disabledApps(): DisabledAppDao } diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt b/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt new file mode 100644 index 00000000..4198315e --- /dev/null +++ b/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt @@ -0,0 +1,52 @@ +package com.f0x1d.logfox.database.entity + +import androidx.room.ColumnInfo +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Entity +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.PrimaryKey +import androidx.room.Query +import androidx.room.Update +import kotlinx.coroutines.flow.Flow + +@Entity +data class DisabledApp( + @ColumnInfo(name = "package_name", index = true) val packageName: String, + @PrimaryKey(autoGenerate = true) val id: Long = 0, +) + +@Dao +interface DisabledAppDao { + + @Query("SELECT * FROM DisabledApp") + suspend fun getAll(): List + + @Query("SELECT * FROM DisabledApp") + fun getAllAsFlow(): Flow> + + @Query("SELECT * FROM DisabledApp WHERE id = :id") + suspend fun getById(id: Long): DisabledApp? + + @Query("SELECT * FROM DisabledApp WHERE id = :id") + fun getByIdAsFlow(id: Long): Flow + + @Query("SELECT * FROM DisabledApp WHERE package_name = :packageName") + suspend fun getByPackageName(packageName: String): DisabledApp? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insert(item: DisabledApp) + + @Update + suspend fun update(item: DisabledApp) + + @Delete + suspend fun delete(item: DisabledApp) + + @Query("DELETE FROM DisabledApp WHERE package_name = :packageName") + suspend fun deleteByPackageName(packageName: String) + + @Query("DELETE FROM DisabledApp") + suspend fun deleteAll() +} diff --git a/core/core-datetime/build.gradle.kts b/core/core-datetime/build.gradle.kts index f36d9903..09bbe541 100644 --- a/core/core-datetime/build.gradle.kts +++ b/core/core-datetime/build.gradle.kts @@ -6,5 +6,5 @@ plugins { android.namespace = "com.f0x1d.logfox.datetime" dependencies { - implementation(project(":core:core-preferences")) + implementation(projects.core.corePreferences) } diff --git a/core/core-navigation/src/main/res/navigation/crashes.xml b/core/core-navigation/src/main/res/navigation/crashes.xml index 01487aae..0e44bf32 100644 --- a/core/core-navigation/src/main/res/navigation/crashes.xml +++ b/core/core-navigation/src/main/res/navigation/crashes.xml @@ -22,6 +22,13 @@ app:exitAnim="@anim/nav_default_exit_anim" app:popEnterAnim="@anim/nav_default_pop_enter_anim" app:popExitAnim="@anim/nav_default_pop_exit_anim"/> + + + diff --git a/core/core-preferences/build.gradle.kts b/core/core-preferences/build.gradle.kts index 4aa13ca2..87d9d013 100644 --- a/core/core-preferences/build.gradle.kts +++ b/core/core-preferences/build.gradle.kts @@ -6,7 +6,7 @@ plugins { android.namespace = "com.f0x1d.logfox.preferences" dependencies { - implementation(project(":core:core-database")) + implementation(projects.core.coreDatabase) implementation(libs.flow.preferences) } diff --git a/core/core-terminals/build.gradle.kts b/core/core-terminals/build.gradle.kts index 27f10874..e06d37b9 100644 --- a/core/core-terminals/build.gradle.kts +++ b/core/core-terminals/build.gradle.kts @@ -10,7 +10,7 @@ android { } dependencies { - implementation(project(":core:core-arch")) + implementation(projects.core.coreArch) implementation(libs.libsu) implementation(libs.bundles.shizuku) diff --git a/core/core-ui-compose/build.gradle.kts b/core/core-ui-compose/build.gradle.kts index 7d484bd7..cdf32dff 100644 --- a/core/core-ui-compose/build.gradle.kts +++ b/core/core-ui-compose/build.gradle.kts @@ -6,5 +6,5 @@ plugins { android.namespace = "com.f0x1d.logfox.ui.compose" dependencies { - implementation(project(":core:core-ui")) + implementation(projects.core.coreUi) } diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt new file mode 100644 index 00000000..0b8221b4 --- /dev/null +++ b/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt @@ -0,0 +1,65 @@ +package com.f0x1d.logfox.ui.compose.component.search + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SearchBar +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TopSearchBar( + query: String, + onQueryChange: (String) -> Unit, + onSearch: (String) -> Unit, + active: Boolean, + onActiveChange: (Boolean) -> Unit, + modifier: Modifier = Modifier, + verticalPadding: Dp = DefaultVerticalPadding, + horizontalPadding: Dp = DefaultHorizontalPadding, + enabled: Boolean = true, + placeholder: @Composable (() -> Unit)? = null, + leadingIcon: @Composable (() -> Unit)? = null, + trailingIcon: @Composable (() -> Unit)? = null, + content: @Composable ColumnScope.() -> Unit, +) { + Surface(modifier = modifier) { + val searchBarVerticalPadding by animateDpAsState( + targetValue = if (active) 0.dp else verticalPadding, + label = "Search bar vertical padding", + ) + val searchBarHorizontalPadding by animateDpAsState( + targetValue = if (active) 0.dp else horizontalPadding, + label = "Search bar horizontal padding", + ) + + SearchBar( + modifier = Modifier + .fillMaxWidth() + .padding( + vertical = searchBarVerticalPadding, + horizontal = searchBarHorizontalPadding, + ), + query = query, + onQueryChange = onQueryChange, + onSearch = onSearch, + active = active, + onActiveChange = onActiveChange, + enabled = enabled, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + content = content, + ) + } +} + +private val DefaultVerticalPadding = 10.dp +private val DefaultHorizontalPadding = 15.dp diff --git a/core/core-ui/build.gradle.kts b/core/core-ui/build.gradle.kts index c766e068..d904a199 100644 --- a/core/core-ui/build.gradle.kts +++ b/core/core-ui/build.gradle.kts @@ -6,8 +6,8 @@ plugins { android.namespace = "com.f0x1d.logfox.ui" dependencies { - implementation(project(":core:core-arch")) - implementation(project(":core:core-preferences")) + implementation(projects.core.coreArch) + implementation(projects.core.corePreferences) implementation(libs.insetter) implementation(libs.viewpump) diff --git a/core/core-ui/src/main/res/drawable/ic_block.xml b/core/core-ui/src/main/res/drawable/ic_block.xml new file mode 100644 index 00000000..be2fe7fe --- /dev/null +++ b/core/core-ui/src/main/res/drawable/ic_block.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt index b78420b6..ad4db26e 100644 --- a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt @@ -8,16 +8,20 @@ import androidx.navigation.fragment.findNavController import com.f0x1d.logfox.arch.ui.fragment.compose.BaseComposeViewModelFragment import com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose.AppsPickerScreenContent import com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose.AppsPickerScreenListener +import com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose.AppsPickerScreenState import com.f0x1d.logfox.feature.apps.picker.viewmodel.AppsPickerViewModel import com.f0x1d.logfox.feature.apps.picker.viewmodel.resultHandler import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme import dagger.hilt.android.AndroidEntryPoint +import kotlinx.collections.immutable.toImmutableSet +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map @AndroidEntryPoint class AppsPickerFragment: BaseComposeViewModelFragment() { override val viewModel by viewModels() - private val resultHandler by resultHandler() private val listener by lazy { @@ -30,15 +34,29 @@ class AppsPickerFragment: BaseComposeViewModelFragment() { findNavController().popBackStack() } }, + onAppChecked = { app, checked -> resultHandler?.onAppChecked(app, checked) }, onSearchActiveChanged = viewModel::changeSearchActive, onQueryChanged = viewModel::updateQuery, ) } + private val uiState: Flow by lazy { + resultHandler?.let { handler -> + combine(viewModel.uiState, handler.checkedAppPackageNames) { state, checkedApps -> + state to checkedApps + }.map { (state, checkedAppPackageNames) -> + state.copy( + checkedAppPackageNames = checkedAppPackageNames.toImmutableSet(), + multiplySelectionEnabled = handler.supportsMultiplySelection, + ) + } + } ?: viewModel.uiState + } + @Composable override fun Content() { LogFoxTheme { - val state by viewModel.uiState.collectAsState() + val state by uiState.collectAsState(initial = viewModel.currentState) AppsPickerScreenContent( state = state, diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt index 830796fc..77e1f6d4 100644 --- a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt @@ -1,7 +1,6 @@ package com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose import androidx.activity.compose.BackHandler -import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -20,16 +19,16 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.union import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.material3.Checkbox import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.SearchBar -import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -40,74 +39,71 @@ import coil.compose.AsyncImage import com.f0x1d.logfox.model.InstalledApp import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.compose.component.button.NavigationBackButton +import com.f0x1d.logfox.ui.compose.component.search.TopSearchBar import com.f0x1d.logfox.ui.compose.preview.DayNightPreview import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentSetOf @Composable internal fun AppsPickerScreenContent( state: AppsPickerScreenState = AppsPickerScreenState(), listener: AppsPickerScreenListener = MockAppsPickerScreenListener, ) { - Scaffold( - topBar = { - AppsSearchBar( - state = state, - listener = listener, - ) - }, - ) { paddingValues -> - if (state.isLoading) { - LoadingContent(modifier = Modifier.padding(paddingValues)) - } else { - AppsContent( - items = state.apps, - listener = listener, - contentPadding = paddingValues, - ) + CompositionLocalProvider(LocalMultiplySelectionEnabled provides state.multiplySelectionEnabled) { + Scaffold( + topBar = { + AppsSearchBar( + state = state, + listener = listener, + ) + }, + ) { paddingValues -> + if (state.isLoading) { + LoadingContent(modifier = Modifier.padding(paddingValues)) + } else { + AppsContent( + items = state.apps, + checkedItems = state.checkedAppPackageNames, + listener = listener, + contentPadding = paddingValues, + ) + } } - } - BackHandler( - enabled = state.searchActive, - onBack = listener.onBackClicked, - ) + BackHandler( + enabled = state.searchActive, + onBack = listener.onBackClicked, + ) + } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun AppsSearchBar( state: AppsPickerScreenState, listener: AppsPickerScreenListener, modifier: Modifier = Modifier, ) { - Surface(modifier = modifier) { - val searchBarPadding by animateDpAsState( - targetValue = if (state.searchActive) 0.dp else 10.dp, - label = "Search bar padding", + TopSearchBar( + modifier = modifier, + query = state.query, + onQueryChange = listener.onQueryChanged, + onSearch = { /* noop */ }, + active = state.searchActive, + onActiveChange = listener.onSearchActiveChanged, + placeholder = { Text(text = stringResource(id = Strings.apps)) }, + leadingIcon = { NavigationBackButton(onClick = listener.onBackClicked) }, + ) { + AppsContent( + items = state.searchedApps, + checkedItems = state.checkedAppPackageNames, + listener = listener, + contentPadding = WindowInsets.navigationBars + .union(WindowInsets.ime) + .asPaddingValues(), ) - - SearchBar( - modifier = Modifier - .fillMaxWidth() - .padding(searchBarPadding), - query = state.query, - onQueryChange = listener.onQueryChanged, - onSearch = { /* noop */ }, - active = state.searchActive, - onActiveChange = listener.onSearchActiveChanged, - placeholder = { Text(text = stringResource(id = Strings.apps)) }, - leadingIcon = { NavigationBackButton(onClick = listener.onBackClicked) } - ) { - AppsContent( - items = state.searchedApps, - listener = listener, - contentPadding = WindowInsets.navigationBars - .union(WindowInsets.ime) - .asPaddingValues(), - ) - } } } @@ -124,6 +120,7 @@ private fun LoadingContent(modifier: Modifier = Modifier) { @Composable private fun AppsContent( items: ImmutableList, + checkedItems: ImmutableSet, listener: AppsPickerScreenListener, modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(), @@ -140,7 +137,11 @@ private fun AppsContent( Column { AppContent( item = item, + isChecked = remember(checkedItems) { + item.packageName in checkedItems + }, onClick = listener.onAppClicked, + onChecked = listener.onAppChecked, ) if (index != items.lastIndex) { @@ -159,7 +160,9 @@ private fun AppsContent( @Composable private fun AppContent( item: InstalledApp, + isChecked: Boolean, onClick: (InstalledApp) -> Unit, + onChecked: (InstalledApp, Boolean) -> Unit, modifier: Modifier = Modifier, ) { Row( @@ -197,14 +200,24 @@ private fun AppContent( overflow = TextOverflow.Ellipsis, ) } + + if (LocalMultiplySelectionEnabled.current) { + Checkbox( + checked = isChecked, + onCheckedChange = { onChecked(item, it) }, + ) + } } } +private val MockApps = persistentListOf( + InstalledApp("LogFox", "com.f0x1d.logfox"), + InstalledApp("Sense", "com.f0x1d.sense"), +) internal val MockAppsPickerScreenState = AppsPickerScreenState( - apps = persistentListOf( - InstalledApp("LogFox", "com.f0x1d.logfox"), - InstalledApp("Sense", "com.f0x1d.sense") - ), + apps = MockApps, + searchedApps = MockApps, + checkedAppPackageNames = persistentSetOf(MockApps.first().packageName), isLoading = false, ) @@ -218,9 +231,10 @@ private fun AppsPickerScreenContentPreview() = LogFoxTheme { @DayNightPreview @Composable -private fun AppContentPreview() = LogFoxTheme { - AppContent( - item = MockAppsPickerScreenState.apps.first(), - onClick = { }, +private fun AppsPickerSearchScreenContentPreview() = LogFoxTheme { + AppsPickerScreenContent( + state = MockAppsPickerScreenState.copy(searchActive = true), ) } + +private val LocalMultiplySelectionEnabled = compositionLocalOf { false } diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt index c9a7a236..bad1efed 100644 --- a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt @@ -2,11 +2,15 @@ package com.f0x1d.logfox.feature.apps.picker.ui.fragment.picker.compose import com.f0x1d.logfox.model.InstalledApp import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.ImmutableSet import kotlinx.collections.immutable.persistentListOf +import kotlinx.collections.immutable.persistentSetOf data class AppsPickerScreenState( val apps: ImmutableList = persistentListOf(), + val checkedAppPackageNames: ImmutableSet = persistentSetOf(), val searchedApps: ImmutableList = persistentListOf(), + val multiplySelectionEnabled: Boolean = true, val isLoading: Boolean = true, val searchActive: Boolean = false, val query: String = "", @@ -15,6 +19,7 @@ data class AppsPickerScreenState( data class AppsPickerScreenListener( val onBackClicked: () -> Unit, val onAppClicked: (InstalledApp) -> Unit, + val onAppChecked: (InstalledApp, Boolean) -> Unit, val onSearchActiveChanged: (Boolean) -> Unit, val onQueryChanged: (String) -> Unit, ) @@ -22,6 +27,7 @@ data class AppsPickerScreenListener( internal val MockAppsPickerScreenListener = AppsPickerScreenListener( onBackClicked = { }, onAppClicked = { }, + onAppChecked = { _, _ -> }, onSearchActiveChanged = { }, onQueryChanged = { }, ) diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt index 4b68446d..4d3e4a3b 100644 --- a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt @@ -4,10 +4,17 @@ import android.annotation.SuppressLint import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.f0x1d.logfox.model.InstalledApp +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf interface AppsPickerResultHandler { + val supportsMultiplySelection: Boolean get() = false + val checkedAppPackageNames: Flow> get() = flowOf(emptySet()) + + fun onAppChecked(app: InstalledApp, checked: Boolean) = Unit + // pass true to close fragment - fun onAppSelected(app: InstalledApp): Boolean + fun onAppSelected(app: InstalledApp): Boolean = false } @SuppressLint("RestrictedApi") diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt index 52ef43cb..ddbca2a3 100644 --- a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt +++ b/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt @@ -68,7 +68,8 @@ class AppsPickerViewModel @Inject constructor( query.map { query -> installedApps.filter { app -> - app.title.contains(query) || app.packageName.contains(query) + app.title.contains(query, ignoreCase = true) + || app.packageName.contains(query, ignoreCase = true) } }.flowOn( defaultDispatcher, diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt index be7a3288..4d7b90d1 100644 --- a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt +++ b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt @@ -2,8 +2,9 @@ package com.f0x1d.logfox.feature.crashes.core.controller import android.content.Context import com.f0x1d.logfox.arch.di.IODispatcher -import com.f0x1d.logfox.database.AppDatabase import com.f0x1d.logfox.database.entity.AppCrash +import com.f0x1d.logfox.feature.crashes.core.repository.CrashesRepository +import com.f0x1d.logfox.feature.crashes.core.repository.DisabledAppsRepository import com.f0x1d.logfox.feature.crashes.core.repository.reader.ANRDetector import com.f0x1d.logfox.feature.crashes.core.repository.reader.JNICrashDetector import com.f0x1d.logfox.feature.crashes.core.repository.reader.JavaCrashDetector @@ -22,7 +23,8 @@ interface CrashesController { internal class CrashesControllerImpl @Inject constructor( @ApplicationContext private val context: Context, private val notificationsController: CrashesNotificationsController, - private val database: AppDatabase, + private val crashesRepository: CrashesRepository, + private val disabledAppsRepository: DisabledAppsRepository, private val appPreferences: AppPreferences, @IODispatcher private val ioDispatcher: CoroutineDispatcher, ) : CrashesController { @@ -40,42 +42,48 @@ internal class CrashesControllerImpl @Inject constructor( ANRDetector(context, this::collectCrash), ) - private suspend fun collectCrash(it: AppCrash, lines: List) = withContext(ioDispatcher) { + private suspend fun collectCrash(appCrash: AppCrash, lines: List) { + if (disabledAppsRepository.isDisabledFor(appCrash.packageName)) { + return + } + // Don't handle if already present in data - database.appCrashes().getAllByDateAndTime( - dateAndTime = it.dateAndTime, - packageName = it.packageName + crashesRepository.getAllByDateAndTime( + dateAndTime = appCrash.dateAndTime, + packageName = appCrash.packageName ).also { - if (it.isNotEmpty()) return@withContext + if (it.isNotEmpty()) return } val crashLog = lines.joinToString("\n") { it.content } - val sendNotificationIfNeeded = { appCrash: AppCrash -> - if (appPreferences.showingNotificationsFor(appCrash.crashType)) { - notificationsController.sendErrorNotification(appCrash, crashLog) + val sendNotificationIfNeeded = { crash: AppCrash -> + if (appPreferences.showingNotificationsFor(crash.crashType)) { + notificationsController.sendErrorNotification(crash, crashLog) } } - val logFile = File(logsDir, "${it.dateAndTime}-crash.log").apply { - writeText(crashLog) + val logFile = withContext(ioDispatcher) { + File(logsDir, "${appCrash.dateAndTime}-crash.log").apply { + writeText(crashLog) + } } - val appCrash = it.copy( + val appCrashWithLog = appCrash.copy( logFile = logFile, logDumpFile = null, // TODO: return log dumps! ) - if (appPreferences.collectingFor(appCrash.crashType)) { - val appCrashWithId = appCrash.copy( - id = database.appCrashes().insert(appCrash) + if (appPreferences.collectingFor(appCrashWithLog.crashType)) { + val appCrashWithId = appCrashWithLog.copy( + id = crashesRepository.insert(appCrashWithLog), ) sendNotificationIfNeeded(appCrashWithId) } else { - sendNotificationIfNeeded(appCrash) + sendNotificationIfNeeded(appCrashWithLog) } } } diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt index 8cac7abe..7249bba7 100644 --- a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt +++ b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt @@ -2,6 +2,8 @@ package com.f0x1d.logfox.feature.crashes.core.di import com.f0x1d.logfox.feature.crashes.core.repository.CrashesRepository import com.f0x1d.logfox.feature.crashes.core.repository.CrashesRepositoryImpl +import com.f0x1d.logfox.feature.crashes.core.repository.DisabledAppsRepository +import com.f0x1d.logfox.feature.crashes.core.repository.DisabledAppsRepositoryImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -15,4 +17,9 @@ internal interface RepositoriesModule { fun bindCrashesRepository( crashesRepositoryImpl: CrashesRepositoryImpl, ): CrashesRepository + + @Binds + fun provideDisabledAppsRepository( + disabledAppsRepositoryImpl: DisabledAppsRepositoryImpl, + ): DisabledAppsRepository } diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt index 32cfe0c3..e8119600 100644 --- a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt +++ b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt @@ -7,11 +7,18 @@ import com.f0x1d.logfox.database.entity.AppCrash import com.f0x1d.logfox.feature.crashes.core.controller.CrashesNotificationsController import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext import javax.inject.Inject interface CrashesRepository : DatabaseProxyRepository { + suspend fun getAllByDateAndTime( + dateAndTime: Long, + packageName: String, + ): List + suspend fun insert(appCrash: AppCrash): Long + suspend fun deleteAllByPackageName(appCrash: AppCrash) } @@ -22,7 +29,9 @@ internal class CrashesRepositoryImpl @Inject constructor( ) : CrashesRepository { override fun getAllAsFlow(): Flow> = - database.appCrashes().getAllAsFlow().flowOn(ioDispatcher) + database.appCrashes().getAllAsFlow() + .distinctUntilChanged() + .flowOn(ioDispatcher) override fun getByIdAsFlow(id: Long): Flow = database.appCrashes().getByIdAsFlow(id).flowOn(ioDispatcher) @@ -35,6 +44,20 @@ internal class CrashesRepositoryImpl @Inject constructor( database.appCrashes().getById(id) } + override suspend fun getAllByDateAndTime( + dateAndTime: Long, + packageName: String + ): List = withContext(ioDispatcher) { + database.appCrashes().getAllByDateAndTime( + dateAndTime = dateAndTime, + packageName = packageName, + ) + } + + override suspend fun insert(appCrash: AppCrash): Long = withContext(ioDispatcher) { + database.appCrashes().insert(appCrash) + } + override suspend fun deleteAllByPackageName(appCrash: AppCrash) = withContext(ioDispatcher) { database.appCrashes().getAllByPackageName(appCrash.packageName).forEach { it.deleteAssociatedFiles() diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt new file mode 100644 index 00000000..77b868aa --- /dev/null +++ b/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt @@ -0,0 +1,72 @@ +package com.f0x1d.logfox.feature.crashes.core.repository + +import com.f0x1d.logfox.arch.di.IODispatcher +import com.f0x1d.logfox.arch.repository.DatabaseProxyRepository +import com.f0x1d.logfox.database.AppDatabase +import com.f0x1d.logfox.database.entity.DisabledApp +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.withContext +import javax.inject.Inject + +interface DisabledAppsRepository : DatabaseProxyRepository { + suspend fun isDisabledFor(packageName: String): Boolean + + suspend fun checkApp(packageName: String) + suspend fun checkApp(packageName: String, checked: Boolean) +} + +internal class DisabledAppsRepositoryImpl @Inject constructor( + private val database: AppDatabase, + @IODispatcher private val ioDispatcher: CoroutineDispatcher, +) : DisabledAppsRepository { + + override suspend fun isDisabledFor(packageName: String): Boolean = withContext(ioDispatcher) { + database.disabledApps().getByPackageName(packageName) != null + } + + override suspend fun checkApp(packageName: String) = checkApp( + packageName = packageName, + checked = withContext(ioDispatcher) { + database.disabledApps().getByPackageName(packageName) == null + }, + ) + + override suspend fun checkApp(packageName: String, checked: Boolean) = withContext(ioDispatcher) { + if (checked) { + database.disabledApps().insert(DisabledApp(packageName)) + } else { + database.disabledApps().deleteByPackageName(packageName) + } + } + + override fun getAllAsFlow(): Flow> = + database.disabledApps().getAllAsFlow() + .distinctUntilChanged() + .flowOn(ioDispatcher) + + override fun getByIdAsFlow(id: Long): Flow = + database.disabledApps().getByIdAsFlow(id).flowOn(ioDispatcher) + + override suspend fun getAll(): List = withContext(ioDispatcher) { + database.disabledApps().getAll() + } + + override suspend fun getById(id: Long): DisabledApp? = withContext(ioDispatcher) { + database.disabledApps().getById(id) + } + + override suspend fun update(item: DisabledApp) = withContext(ioDispatcher) { + database.disabledApps().update(item) + } + + override suspend fun delete(item: DisabledApp) = withContext(ioDispatcher) { + database.disabledApps().delete(item) + } + + override suspend fun clear() = withContext(ioDispatcher) { + database.disabledApps().deleteAll() + } +} diff --git a/feature/feature-crashes/build.gradle.kts b/feature/feature-crashes/build.gradle.kts index 070c49ab..b4de008d 100644 --- a/feature/feature-crashes/build.gradle.kts +++ b/feature/feature-crashes/build.gradle.kts @@ -5,8 +5,8 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.crashes" dependencies { - implementation(project(":feature:feature-crashes-core")) + implementation(projects.feature.featureAppsPicker) + implementation(projects.feature.featureCrashesCore) implementation(libs.glide) - ksp(libs.glide.compiler) } diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt index 6be1e0cc..d2e102ba 100644 --- a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt +++ b/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt @@ -8,7 +8,7 @@ import androidx.activity.OnBackPressedCallback import androidx.core.os.bundleOf import androidx.core.view.isVisible import androidx.core.widget.doAfterTextChanged -import androidx.fragment.app.viewModels +import androidx.hilt.navigation.fragment.hiltNavGraphViewModels import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import com.f0x1d.logfox.arch.isHorizontalOrientation @@ -35,7 +35,7 @@ import dev.chrisbanes.insetter.applyInsetter @AndroidEntryPoint class CrashesFragment: BaseViewModelFragment() { - override val viewModel by viewModels() + override val viewModel by hiltNavGraphViewModels(Directions.crashesFragment) private val adapter = CrashesAdapter( click = { @@ -104,6 +104,9 @@ class CrashesFragment: BaseViewModelFragment> = + disabledAppsRepository.getAllAsFlow().map { apps -> + apps.map(DisabledApp::packageName).toSet() + } + + override fun onAppChecked(app: InstalledApp, checked: Boolean) { + viewModelScope.launch { + disabledAppsRepository.checkApp(app.packageName, checked) + } + } + + override fun onAppSelected(app: InstalledApp): Boolean { + viewModelScope.launch { + disabledAppsRepository.checkApp(app.packageName) + } + return false + } + private data class CrashesWithSort( val crashes: List, val sortType: CrashesSort, diff --git a/feature/feature-crashes/src/main/res/menu/crashes_menu.xml b/feature/feature-crashes/src/main/res/menu/crashes_menu.xml index 58c6d6a1..4155f688 100644 --- a/feature/feature-crashes/src/main/res/menu/crashes_menu.xml +++ b/feature/feature-crashes/src/main/res/menu/crashes_menu.xml @@ -8,6 +8,12 @@ android:title="@string/sort" app:showAsAction="ifRoom" /> + + UserFilter) = update(newValue()) override fun getAllAsFlow(): Flow> = - database.userFilters().getAllAsFlow().flowOn(ioDispatcher) + database.userFilters().getAllAsFlow() + .distinctUntilChanged() + .flowOn(ioDispatcher) override fun getByIdAsFlow(id: Long): Flow = database.userFilters().getByIdAsFlow(id).flowOn(ioDispatcher) diff --git a/feature/feature-filters/build.gradle.kts b/feature/feature-filters/build.gradle.kts index 71d40c00..e00c6fad 100644 --- a/feature/feature-filters/build.gradle.kts +++ b/feature/feature-filters/build.gradle.kts @@ -5,11 +5,8 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.filters" dependencies { - implementation(project(":feature:feature-filters-core")) - implementation(project(":feature:feature-apps-picker")) + implementation(projects.feature.featureAppsPicker) + implementation(projects.feature.featureFiltersCore) implementation(libs.gson) - - implementation(libs.glide) - ksp(libs.glide.compiler) } diff --git a/feature/feature-logging/build.gradle.kts b/feature/feature-logging/build.gradle.kts index e89d798c..42350932 100644 --- a/feature/feature-logging/build.gradle.kts +++ b/feature/feature-logging/build.gradle.kts @@ -5,8 +5,8 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.logging" dependencies { - implementation(project(":feature:feature-crashes-core")) - implementation(project(":feature:feature-filters-core")) - implementation(project(":feature:feature-logging-core")) - implementation(project(":feature:feature-recordings-core")) + implementation(projects.feature.featureCrashesCore) + implementation(projects.feature.featureFiltersCore) + implementation(projects.feature.featureLoggingCore) + implementation(projects.feature.featureRecordingsCore) } diff --git a/feature/feature-recordings-core/build.gradle.kts b/feature/feature-recordings-core/build.gradle.kts index 39630fa2..be5c1e3f 100644 --- a/feature/feature-recordings-core/build.gradle.kts +++ b/feature/feature-recordings-core/build.gradle.kts @@ -5,5 +5,5 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.recordings.core" dependencies { - implementation(project(":feature:feature-logging-core")) + implementation(projects.feature.featureLoggingCore) } diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt b/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt index f084f013..9f1a24b3 100644 --- a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt +++ b/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt @@ -16,6 +16,7 @@ import com.f0x1d.logfox.terminals.base.Terminal import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext import java.io.File @@ -113,7 +114,9 @@ internal class RecordingsRepositoryImpl @Inject constructor( ) override fun getAllAsFlow(): Flow> = - database.logRecordings().getAllAsFlow().flowOn(ioDispatcher) + database.logRecordings().getAllAsFlow() + .distinctUntilChanged() + .flowOn(ioDispatcher) override fun getByIdAsFlow(id: Long): Flow = database.logRecordings().getByIdAsFlow(id).flowOn(ioDispatcher) diff --git a/feature/feature-recordings/build.gradle.kts b/feature/feature-recordings/build.gradle.kts index 200c093f..210a6780 100644 --- a/feature/feature-recordings/build.gradle.kts +++ b/feature/feature-recordings/build.gradle.kts @@ -5,5 +5,5 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.recordings" dependencies { - implementation(project(":feature:feature-recordings-core")) + implementation(projects.feature.featureRecordingsCore) } diff --git a/strings/src/main/res/values-ru/strings.xml b/strings/src/main/res/values-ru/strings.xml index 06c918a2..0770e3ae 100644 --- a/strings/src/main/res/values-ru/strings.xml +++ b/strings/src/main/res/values-ru/strings.xml @@ -154,4 +154,5 @@ Использовать разные каналы уведомлений для уведомлений о сбоях Открывать вкладку сбоев при запуске Перенос строк в деталях лога + Черный список diff --git a/strings/src/main/res/values/strings.xml b/strings/src/main/res/values/strings.xml index 9bcf3a15..19b2c062 100644 --- a/strings/src/main/res/values/strings.xml +++ b/strings/src/main/res/values/strings.xml @@ -163,4 +163,5 @@ Use separate notifications channels for crashes notifications Open crashes page on startup Wrap log lines in details + Blacklist From d1e292a22ae905987b86b3369cb7991e84472547 Mon Sep 17 00:00:00 2001 From: F0x1d Date: Thu, 15 Aug 2024 00:57:07 +0300 Subject: [PATCH 5/9] [build]: renamed modules --- app/build.gradle.kts | 26 ++++-------------- .../main/kotlin/extensions/Dependencies.kt | 18 ++++++------ core/{core-arch => arch}/.gitignore | 0 core/{core-arch => arch}/build.gradle.kts | 0 .../src/main/AndroidManifest.xml | 0 .../main/kotlin/com/f0x1d/logfox/arch/API.kt | 0 .../com/f0x1d/logfox/arch/ContextExt.kt | 0 .../kotlin/com/f0x1d/logfox/arch/FileExt.kt | 0 .../com/f0x1d/logfox/arch/NotificationExt.kt | 0 .../com/f0x1d/logfox/arch/PendingIntents.kt | 0 .../logfox/arch/adapter/BaseListAdapter.kt | 0 .../f0x1d/logfox/arch/annotations/GsonSkip.kt | 0 .../f0x1d/logfox/arch/di/DispatchersModule.kt | 0 .../com/f0x1d/logfox/arch/di/GsonModule.kt | 0 .../com/f0x1d/logfox/arch/di/UtilsModule.kt | 0 .../f0x1d/logfox/arch/io/OutputStreamExt.kt | 0 .../logfox/arch/io/ZipOutputStreamExt.kt | 0 .../logfox/arch/receiver/CopyReceiver.kt | 0 .../logfox/arch/repository/BaseRepository.kt | 0 .../repository/DatabaseProxyRepository.kt | 0 .../com/f0x1d/logfox/arch/ui/SnackbarExt.kt | 0 .../com/f0x1d/logfox/arch/ui/WindowExt.kt | 0 .../logfox/arch/ui/activity/BaseActivity.kt | 0 .../arch/ui/activity/BaseViewModelActivity.kt | 0 .../arch/ui/base/SimpleLifecycleOwner.kt | 0 .../logfox/arch/ui/dialog/BaseBottomSheet.kt | 0 .../ui/dialog/BaseViewModelBottomSheet.kt | 0 .../logfox/arch/ui/fragment/BaseFragment.kt | 0 .../arch/ui/fragment/BaseViewModelFragment.kt | 0 .../fragment/compose/BaseComposeFragment.kt | 0 .../compose/BaseComposeViewModelFragment.kt | 0 .../arch/ui/viewholder/BaseViewHolder.kt | 0 .../arch/viewmodel/BaseStateViewModel.kt | 0 .../logfox/arch/viewmodel/BaseViewModel.kt | 0 .../com/f0x1d/logfox/arch/viewmodel/Event.kt | 0 .../color/navbar_transparent_background.xml | 0 .../src/main/res/layout/fragment_compose.xml | 0 .../src/main/res/values/colors.xml | 0 core/{core-database => database}/.gitignore | 0 .../build.gradle.kts | 2 +- .../10.json | 0 .../11.json | 0 .../12.json | 0 .../13.json | 0 .../14.json | 0 .../15.json | 0 .../16.json | 0 .../17.json | 0 .../7.json | 0 .../8.json | 0 .../9.json | 0 .../com/f0x1d/logfox/database/AppDatabase.kt | 0 .../f0x1d/logfox/database/di/RoomModule.kt | 0 .../f0x1d/logfox/database/entity/AppCrash.kt | 0 .../logfox/database/entity/DisabledApp.kt | 0 .../logfox/database/entity/LogRecording.kt | 0 .../logfox/database/entity/UserFilter.kt | 0 core/{core-datetime => datetime}/.gitignore | 0 .../build.gradle.kts | 2 +- .../com/f0x1d/logfox/datetime/ContextExt.kt | 0 .../logfox/datetime/DateTimeFormatter.kt | 0 .../datetime/DateTimeFormatterModule.kt | 0 .../.gitignore | 0 .../build.gradle.kts | 0 .../com/f0x1d/logfox/navigation/Navigation.kt | 0 .../src/main/res/navigation/crashes.xml | 0 .../src/main/res/navigation/logs.xml | 0 .../src/main/res/navigation/nav_graph.xml | 0 .../src/main/res/navigation/recordings.xml | 0 .../src/main/res/navigation/settings.xml | 0 .../.gitignore | 0 .../build.gradle.kts | 2 +- .../preferences/shared/AppPreferences.kt | 0 .../logfox/preferences/shared/ContextExt.kt | 0 .../shared/base/BasePreferences.kt | 0 .../preferences/shared/crashes/CrashesSort.kt | 0 core/{core-terminals => terminals}/.gitignore | 0 .../build.gradle.kts | 2 +- .../src/main/AndroidManifest.xml | 0 .../aidl/com/f0x1d/logfox/IUserService.aidl | 0 .../logfox/model/terminal/TerminalResult.aidl | 0 .../com/f0x1d/logfox/di/TerminalsModule.kt | 0 .../com/f0x1d/logfox/service/UserService.kt | 0 .../f0x1d/logfox/terminals/DefaultTerminal.kt | 0 .../f0x1d/logfox/terminals/RootTerminal.kt | 0 .../f0x1d/logfox/terminals/ShizukuTerminal.kt | 0 .../f0x1d/logfox/terminals/base/Terminal.kt | 0 .../src/main/res/values-it/strings.xml | 0 .../src/main/res/values-pt-rBR/strings.xml | 0 .../src/main/res/values-ru/strings.xml | 0 .../src/main/res/values-tr/strings.xml | 0 .../src/main/res/values-zh-rCN/strings.xml | 0 .../src/main/res/values/strings.xml | 0 core/{core-tests => tests}/.gitignore | 0 core/{core-tests => tests}/build.gradle.kts | 0 .../f0x1d/logfox/core/tests/ScreenshotTest.kt | 0 .../SemanticsNodeInteractionsProviderExt.kt | 0 .../.gitignore | 0 .../build.gradle.kts | 2 +- .../component/button/NavigationBackButton.kt | 0 .../ui/compose/component/button/RichButton.kt | 0 .../compose/component/search/TopSearchBar.kt | 0 .../ui/compose/preview/DayNightPreview.kt | 0 .../f0x1d/logfox/ui/compose/theme/Color.kt | 0 .../f0x1d/logfox/ui/compose/theme/Theme.kt | 0 .../com/f0x1d/logfox/ui/compose/theme/Type.kt | 0 .../src/main/res/values/font_certs.xml | 0 core/{core-ui => ui}/.gitignore | 0 core/{core-ui => ui}/build.gradle.kts | 4 +-- .../main/kotlin/com/f0x1d/logfox/ui/Icons.kt | 0 .../com/f0x1d/logfox/ui/density/PxExt.kt | 0 .../com/f0x1d/logfox/ui/di/ViewPumpModule.kt | 0 .../logfox/ui/dialog/AreYouSureDialogExt.kt | 0 .../logfox/ui/glide/icon/IconDataFetcher.kt | 0 .../logfox/ui/glide/icon/IconGlideModule.kt | 0 .../logfox/ui/glide/icon/IconModelLoader.kt | 0 .../ui/glide/icon/IconModelLoaderFactory.kt | 0 .../logfox/ui/interceptor/FontsInterceptor.kt | 0 .../CustomApplyInsetsNavigationRailView.kt | 0 .../logfox/ui/view/CustomNestedScrollView.kt | 0 .../kotlin/com/f0x1d/logfox/ui/view/FABExt.kt | 0 .../com/f0x1d/logfox/ui/view/ImageViewExt.kt | 0 .../com/f0x1d/logfox/ui/view/MenuExt.kt | 0 .../ui/view/OnlyUserCheckedChangeListener.kt | 0 .../com/f0x1d/logfox/ui/view/PreferenceExt.kt | 0 .../com/f0x1d/logfox/ui/view/ToolbarExt.kt | 0 .../ui/view/loglevel/LogLevelExtensions.kt | 0 .../logfox/ui/view/loglevel/LogLevelView.kt | 0 .../res/color/item_log_background_ripple.xml | 0 .../item_log_level_background.xml | 0 .../src/main/res/drawable/ic_adb.xml | 0 .../src/main/res/drawable/ic_add.xml | 0 .../src/main/res/drawable/ic_add_link.xml | 0 .../src/main/res/drawable/ic_alert.xml | 0 .../src/main/res/drawable/ic_android.xml | 0 .../src/main/res/drawable/ic_android_anim.xml | 0 .../src/main/res/drawable/ic_android_avd.xml | 0 .../src/main/res/drawable/ic_archive.xml | 0 .../src/main/res/drawable/ic_arrow_back.xml | 0 .../main/res/drawable/ic_arrow_drop_down.xml | 0 .../src/main/res/drawable/ic_block.xml | 0 .../src/main/res/drawable/ic_bug.xml | 0 .../src/main/res/drawable/ic_bug_anim.xml | 0 .../src/main/res/drawable/ic_bug_avd.xml | 0 .../main/res/drawable/ic_bug_notification.xml | 0 .../src/main/res/drawable/ic_checklist.xml | 0 .../src/main/res/drawable/ic_clear.xml | 0 .../src/main/res/drawable/ic_clear_all.xml | 0 .../src/main/res/drawable/ic_copy.xml | 0 .../src/main/res/drawable/ic_delete.xml | 0 .../src/main/res/drawable/ic_dialog_adb.xml | 0 .../res/drawable/ic_dialog_date_format.xml | 0 .../src/main/res/drawable/ic_dialog_eye.xml | 0 .../src/main/res/drawable/ic_dialog_list.xml | 0 .../ic_dialog_notification_important.xml | 0 .../main/res/drawable/ic_dialog_terminal.xml | 0 .../res/drawable/ic_dialog_text_fields.xml | 0 .../src/main/res/drawable/ic_dialog_theme.xml | 0 .../res/drawable/ic_dialog_time_format.xml | 0 .../src/main/res/drawable/ic_dialog_timer.xml | 0 .../main/res/drawable/ic_dialog_warning.xml | 0 .../src/main/res/drawable/ic_export.xml | 0 .../src/main/res/drawable/ic_eye.xml | 0 .../src/main/res/drawable/ic_filter.xml | 0 .../src/main/res/drawable/ic_info.xml | 0 .../res/drawable/ic_launcher_foreground.xml | 0 .../src/main/res/drawable/ic_logfox.xml | 0 .../src/main/res/drawable/ic_logfox_anim.xml | 0 .../src/main/res/drawable/ic_logfox_avd.xml | 0 .../main/res/drawable/ic_notifications.xml | 0 .../src/main/res/drawable/ic_pause.xml | 0 .../src/main/res/drawable/ic_play.xml | 0 .../src/main/res/drawable/ic_recording.xml | 0 .../main/res/drawable/ic_recording_anim.xml | 0 .../main/res/drawable/ic_recording_avd.xml | 0 .../drawable/ic_recording_notification.xml | 0 .../ic_recording_play_notification.xml | 0 .../src/main/res/drawable/ic_save.xml | 0 .../src/main/res/drawable/ic_search.xml | 0 .../src/main/res/drawable/ic_select.xml | 0 .../src/main/res/drawable/ic_select_all.xml | 0 .../src/main/res/drawable/ic_settings.xml | 0 .../main/res/drawable/ic_settings_anim.xml | 0 .../src/main/res/drawable/ic_settings_avd.xml | 0 .../main/res/drawable/ic_settings_code.xml | 0 .../main/res/drawable/ic_settings_crashes.xml | 0 .../res/drawable/ic_settings_handyman.xml | 0 .../main/res/drawable/ic_settings_info.xml | 0 .../drawable/ic_settings_notifications.xml | 0 .../main/res/drawable/ic_settings_person.xml | 0 .../res/drawable/ic_settings_releases.xml | 0 .../main/res/drawable/ic_settings_service.xml | 0 .../src/main/res/drawable/ic_settings_ui.xml | 0 .../main/res/drawable/ic_settings_users.xml | 0 .../main/res/drawable/ic_settings_warning.xml | 0 .../src/main/res/drawable/ic_share.xml | 0 .../src/main/res/drawable/ic_sort.xml | 0 .../src/main/res/drawable/ic_square_root.xml | 0 .../src/main/res/drawable/ic_stop.xml | 0 .../src/main/res/drawable/ic_terminal.xml | 0 .../main/res/drawable/item_log_background.xml | 0 .../drawable/item_log_level_background.xml | 0 .../drawable/placeholder_icon_background.xml | 0 .../src/main/res/font/google_sans.ttf | Bin .../src/main/res/font/google_sans_medium.ttf | Bin .../src/main/res/layout/dialog_text.xml | 0 .../src/main/res/layout/fragment_settings.xml | 0 .../src/main/res/values-night/colors.xml | 0 .../src/main/res/values/colors.xml | 0 .../src/main/res/values/ids.xml | 0 .../src/main/res/values/styles.xml | 1 + .../src/main/res/values/themes.xml | 0 .../.gitignore | 0 .../build.gradle.kts | 0 .../ui/fragment/picker/AppsPickerFragment.kt | 0 .../picker/compose/AppsPickerScreenContent.kt | 0 .../picker/compose/AppsPickerScreenState.kt | 0 .../viewmodel/AppsPickerResultHandler.kt | 0 .../picker/viewmodel/AppsPickerViewModel.kt | 0 .../.gitignore | 0 .../build.gradle.kts | 0 .../core/controller/CrashesController.kt | 0 .../CrashesNotificationsController.kt | 0 .../crashes/core/di/ControllersModule.kt | 0 .../crashes/core/di/RepositoriesModule.kt | 0 .../core/repository/CrashesRepository.kt | 0 .../core/repository/DisabledAppsRepository.kt | 0 .../core/repository/reader/ANRDetector.kt | 0 .../repository/reader/JNICrashDetector.kt | 0 .../repository/reader/JavaCrashDetector.kt | 2 +- .../reader/base/BaseCrashDetector.kt | 0 .../repository/reader/base/DefaultChecker.kt | 0 .../{feature-crashes => crashes}/.gitignore | 0 .../build.gradle.kts | 4 +-- .../feature/crashes/adapter/CrashesAdapter.kt | 0 .../crashes/di/AppCrashesViewModelModule.kt | 0 .../crashes/di/CrashDetailsViewModelModule.kt | 0 .../ui/fragment/CrashDetailsFragment.kt | 0 .../ui/fragment/list/AppCrashesFragment.kt | 0 .../ui/fragment/list/CrashesFragment.kt | 0 .../crashes/ui/viewholder/CrashViewHolder.kt | 0 .../viewmodel/CrashDetailsViewModel.kt | 0 .../viewmodel/list/AppCrashesViewModel.kt | 0 .../viewmodel/list/CrashesViewModel.kt | 0 .../src/main/res/layout/dialog_sorting.xml | 0 .../main/res/layout/fragment_app_crashes.xml | 0 .../res/layout/fragment_crash_details.xml | 0 .../src/main/res/layout/fragment_crashes.xml | 0 .../src/main/res/layout/item_crash.xml | 0 .../src/main/res/layout/item_sort.xml | 0 .../main/res/layout/placeholder_crashes.xml | 0 .../src/main/res/menu/crash_details_menu.xml | 0 .../src/main/res/menu/crashes_menu.xml | 0 feature/feature-logging/build.gradle.kts | 12 -------- .../.gitignore | 0 .../build.gradle.kts | 0 .../filters/core/di/RepositoriesModule.kt | 0 .../core/repository/FiltersRepository.kt | 0 .../{feature-filters => filters}/.gitignore | 0 .../build.gradle.kts | 4 +-- .../feature/filters/adapter/FiltersAdapter.kt | 0 .../filters/di/EditFilterViewModelModule.kt | 0 .../filters/ui/fragment/EditFilterFragment.kt | 0 .../filters/ui/fragment/FiltersFragment.kt | 0 .../filters/ui/viewholder/FilterViewHolder.kt | 0 .../filters/viewmodel/EditFilterViewModel.kt | 0 .../filters/viewmodel/FiltersViewModel.kt | 0 .../main/res/layout/fragment_edit_filter.xml | 0 .../src/main/res/layout/fragment_filters.xml | 0 .../src/main/res/layout/item_filter.xml | 0 .../main/res/layout/placeholder_filters.xml | 0 .../src/main/res/menu/edit_filter_menu.xml | 0 .../src/main/res/menu/filters_menu.xml | 0 .../.gitignore | 0 .../build.gradle.kts | 0 .../logging/core/di/RepositoriesModule.kt | 0 .../feature/logging/core/di/StoresModule.kt | 0 .../feature/logging/core/model/LogLinesExt.kt | 0 .../core/repository/LoggingRepository.kt | 0 .../logging/core/store/LoggingStore.kt | 0 .../{feature-logging => logging}/.gitignore | 0 feature/logging/build.gradle.kts | 12 ++++++++ .../src/main/AndroidManifest.xml | 0 .../feature/logging/adapter/LogsAdapter.kt | 0 .../feature/logging/di/LogsViewModelModule.kt | 0 .../feature/logging/service/LoggingService.kt | 0 .../MainActivityPendingIntentProvider.kt | 0 .../logging/ui/dialog/SearchBottomSheet.kt | 0 .../ui/fragment/LogsExtendedCopyFragment.kt | 0 .../logging/ui/fragment/LogsFragment.kt | 0 .../logging/ui/viewholder/LogViewHolder.kt | 0 .../logging/viewmodel/LogsViewModel.kt | 0 .../f0x1d/feature/logging/viewmodel/UriExt.kt | 0 .../src/main/res/layout/fragment_logs.xml | 0 .../layout/fragment_logs_extended_copy.xml | 0 .../src/main/res/layout/item_log.xml | 0 .../src/main/res/layout/placeholder_logs.xml | 0 .../src/main/res/layout/sheet_search.xml | 0 .../src/main/res/menu/log_menu.xml | 0 .../src/main/res/menu/logs_menu.xml | 0 .../.gitignore | 0 .../build.gradle.kts | 2 +- .../src/main/AndroidManifest.xml | 0 .../core/controller/RecordingController.kt | 0 .../RecordingNotificationController.kt | 0 .../core/controller/reader/RecordingReader.kt | 0 .../recordings/core/di/ControllersModule.kt | 0 .../recordings/core/di/RepositoriesModule.kt | 0 .../core/receiver/RecordingReceiver.kt | 0 .../core/repository/RecordingsRepository.kt | 0 .../.gitignore | 0 .../build.gradle.kts | 2 +- .../recordings/adapter/RecordingsAdapter.kt | 0 .../recordings/di/RecordingViewModelModule.kt | 0 .../ui/dialog/RecordingBottomSheet.kt | 0 .../ui/fragment/RecordingsFragment.kt | 0 .../ui/viewholder/RecordingViewHolder.kt | 0 .../viewmodel/RecordingViewModel.kt | 0 .../viewmodel/RecordingsViewModel.kt | 0 .../main/res/layout/fragment_recordings.xml | 0 .../src/main/res/layout/item_recording.xml | 0 .../res/layout/placeholder_recordings.xml | 0 .../src/main/res/layout/sheet_recording.xml | 0 .../src/main/res/menu/recordings_menu.xml | 0 .../{feature-settings => settings}/.gitignore | 0 .../build.gradle.kts | 0 .../logfox/feature/settings/IntArrayExt.kt | 0 .../settings/LoggingServiceDelegate.kt | 0 .../ui/fragment/SettingsCrashesFragment.kt | 0 .../ui/fragment/SettingsLinksFragment.kt | 0 .../ui/fragment/SettingsMenuFragment.kt | 0 .../fragment/SettingsNotificationsFragment.kt | 0 .../ui/fragment/SettingsServiceFragment.kt | 0 .../ui/fragment/SettingsUIFragment.kt | 0 .../fragment/base/BasePreferenceFragment.kt | 0 .../res/layout/preference_material_switch.xml | 0 .../main/res/layout/preference_warning.xml | 0 .../src/main/res/values/ids.xml | 0 .../src/main/res/xml/settings_crashes.xml | 0 .../src/main/res/xml/settings_links.xml | 0 .../src/main/res/xml/settings_menu.xml | 0 .../main/res/xml/settings_notifications.xml | 0 .../src/main/res/xml/settings_service.xml | 0 .../src/main/res/xml/settings_ui.xml | 0 feature/{feature-setup => setup}/.gitignore | 0 .../{feature-setup => setup}/build.gradle.kts | 0 .../setup/ui/fragment/setup/SetupFragment.kt | 0 .../setup/compose/SetupScreenContent.kt | 0 .../setup/compose/SetupScreenState.kt | 0 .../feature/setup/viewmodel/SetupViewModel.kt | 0 .../setup/compose/SetupScreenContentTest.kt | 0 ...houldOpenAdbDialogOnSetupScreenContent.png | Bin ...houldShowAdbDialogOnSetupScreenContent.png | Bin ...tTest.shouldShowDarkSetupScreenContent.png | Bin ...ntentTest.shouldShowSetupScreenContent.png | Bin 355 files changed, 42 insertions(+), 55 deletions(-) rename core/{core-arch => arch}/.gitignore (100%) rename core/{core-arch => arch}/build.gradle.kts (100%) rename core/{core-arch => arch}/src/main/AndroidManifest.xml (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/API.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/adapter/BaseListAdapter.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/di/DispatchersModule.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/di/UtilsModule.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/repository/BaseRepository.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/repository/DatabaseProxyRepository.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/SnackbarExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/WindowExt.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/ui/viewholder/BaseViewHolder.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt (100%) rename core/{core-arch => arch}/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt (100%) rename core/{core-arch => arch}/src/main/res/color/navbar_transparent_background.xml (100%) rename core/{core-arch => arch}/src/main/res/layout/fragment_compose.xml (100%) rename core/{core-arch => arch}/src/main/res/values/colors.xml (100%) rename core/{core-database => database}/.gitignore (100%) rename core/{core-database => database}/build.gradle.kts (89%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/10.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/11.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/12.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/13.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/14.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/15.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/16.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/17.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/7.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/8.json (100%) rename core/{core-database => database}/schemas/com.f0x1d.logfox.database.AppDatabase/9.json (100%) rename core/{core-database => database}/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt (100%) rename core/{core-database => database}/src/main/kotlin/com/f0x1d/logfox/database/di/RoomModule.kt (100%) rename core/{core-database => database}/src/main/kotlin/com/f0x1d/logfox/database/entity/AppCrash.kt (100%) rename core/{core-database => database}/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt (100%) rename core/{core-database => database}/src/main/kotlin/com/f0x1d/logfox/database/entity/LogRecording.kt (100%) rename core/{core-database => database}/src/main/kotlin/com/f0x1d/logfox/database/entity/UserFilter.kt (100%) rename core/{core-datetime => datetime}/.gitignore (100%) rename core/{core-datetime => datetime}/build.gradle.kts (73%) rename core/{core-datetime => datetime}/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt (100%) rename core/{core-datetime => datetime}/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt (100%) rename core/{core-datetime => datetime}/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt (100%) rename core/{core-navigation => navigation}/.gitignore (100%) rename core/{core-navigation => navigation}/build.gradle.kts (100%) rename core/{core-navigation => navigation}/src/main/kotlin/com/f0x1d/logfox/navigation/Navigation.kt (100%) rename core/{core-navigation => navigation}/src/main/res/navigation/crashes.xml (100%) rename core/{core-navigation => navigation}/src/main/res/navigation/logs.xml (100%) rename core/{core-navigation => navigation}/src/main/res/navigation/nav_graph.xml (100%) rename core/{core-navigation => navigation}/src/main/res/navigation/recordings.xml (100%) rename core/{core-navigation => navigation}/src/main/res/navigation/settings.xml (100%) rename core/{core-preferences => preferences}/.gitignore (100%) rename core/{core-preferences => preferences}/build.gradle.kts (79%) rename core/{core-preferences => preferences}/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt (100%) rename core/{core-preferences => preferences}/src/main/kotlin/com/f0x1d/logfox/preferences/shared/ContextExt.kt (100%) rename core/{core-preferences => preferences}/src/main/kotlin/com/f0x1d/logfox/preferences/shared/base/BasePreferences.kt (100%) rename core/{core-preferences => preferences}/src/main/kotlin/com/f0x1d/logfox/preferences/shared/crashes/CrashesSort.kt (100%) rename core/{core-terminals => terminals}/.gitignore (100%) rename core/{core-terminals => terminals}/build.gradle.kts (85%) rename core/{core-terminals => terminals}/src/main/AndroidManifest.xml (100%) rename core/{core-terminals => terminals}/src/main/aidl/com/f0x1d/logfox/IUserService.aidl (100%) rename core/{core-terminals => terminals}/src/main/aidl/com/f0x1d/logfox/model/terminal/TerminalResult.aidl (100%) rename core/{core-terminals => terminals}/src/main/kotlin/com/f0x1d/logfox/di/TerminalsModule.kt (100%) rename core/{core-terminals => terminals}/src/main/kotlin/com/f0x1d/logfox/service/UserService.kt (100%) rename core/{core-terminals => terminals}/src/main/kotlin/com/f0x1d/logfox/terminals/DefaultTerminal.kt (100%) rename core/{core-terminals => terminals}/src/main/kotlin/com/f0x1d/logfox/terminals/RootTerminal.kt (100%) rename core/{core-terminals => terminals}/src/main/kotlin/com/f0x1d/logfox/terminals/ShizukuTerminal.kt (100%) rename core/{core-terminals => terminals}/src/main/kotlin/com/f0x1d/logfox/terminals/base/Terminal.kt (100%) rename core/{core-terminals => terminals}/src/main/res/values-it/strings.xml (100%) rename core/{core-terminals => terminals}/src/main/res/values-pt-rBR/strings.xml (100%) rename core/{core-terminals => terminals}/src/main/res/values-ru/strings.xml (100%) rename core/{core-terminals => terminals}/src/main/res/values-tr/strings.xml (100%) rename core/{core-terminals => terminals}/src/main/res/values-zh-rCN/strings.xml (100%) rename core/{core-terminals => terminals}/src/main/res/values/strings.xml (100%) rename core/{core-tests => tests}/.gitignore (100%) rename core/{core-tests => tests}/build.gradle.kts (100%) rename core/{core-tests => tests}/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt (100%) rename core/{core-tests => tests}/src/main/kotlin/com/f0x1d/logfox/core/tests/compose/SemanticsNodeInteractionsProviderExt.kt (100%) rename core/{core-ui-compose => ui-compose}/.gitignore (100%) rename core/{core-ui-compose => ui-compose}/build.gradle.kts (77%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/preview/DayNightPreview.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Color.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Theme.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Type.kt (100%) rename core/{core-ui-compose => ui-compose}/src/main/res/values/font_certs.xml (100%) rename core/{core-ui => ui}/.gitignore (100%) rename core/{core-ui => ui}/build.gradle.kts (73%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/Icons.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/density/PxExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/di/ViewPumpModule.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/dialog/AreYouSureDialogExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconDataFetcher.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconGlideModule.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoader.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoaderFactory.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/interceptor/FontsInterceptor.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomApplyInsetsNavigationRailView.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomNestedScrollView.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/FABExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/ImageViewExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/MenuExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/OnlyUserCheckedChangeListener.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/ToolbarExt.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelExtensions.kt (100%) rename core/{core-ui => ui}/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelView.kt (100%) rename core/{core-ui => ui}/src/main/res/color/item_log_background_ripple.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable-ldrtl/item_log_level_background.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_adb.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_add.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_add_link.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_alert.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_android.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_android_anim.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_android_avd.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_archive.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_arrow_back.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_arrow_drop_down.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_block.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_bug.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_bug_anim.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_bug_avd.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_bug_notification.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_checklist.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_clear.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_clear_all.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_copy.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_delete.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_adb.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_date_format.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_eye.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_list.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_notification_important.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_terminal.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_text_fields.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_theme.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_time_format.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_timer.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_dialog_warning.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_export.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_eye.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_filter.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_info.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_launcher_foreground.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_logfox.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_logfox_anim.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_logfox_avd.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_notifications.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_pause.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_play.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_recording.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_recording_anim.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_recording_avd.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_recording_notification.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_recording_play_notification.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_save.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_search.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_select.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_select_all.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_anim.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_avd.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_code.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_crashes.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_handyman.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_info.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_notifications.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_person.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_releases.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_service.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_ui.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_users.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_settings_warning.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_share.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_sort.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_square_root.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_stop.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/ic_terminal.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/item_log_background.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/item_log_level_background.xml (100%) rename core/{core-ui => ui}/src/main/res/drawable/placeholder_icon_background.xml (100%) rename core/{core-ui => ui}/src/main/res/font/google_sans.ttf (100%) rename core/{core-ui => ui}/src/main/res/font/google_sans_medium.ttf (100%) rename core/{core-ui => ui}/src/main/res/layout/dialog_text.xml (100%) rename core/{core-ui => ui}/src/main/res/layout/fragment_settings.xml (100%) rename core/{core-ui => ui}/src/main/res/values-night/colors.xml (100%) rename core/{core-ui => ui}/src/main/res/values/colors.xml (100%) rename core/{core-ui => ui}/src/main/res/values/ids.xml (100%) rename core/{core-ui => ui}/src/main/res/values/styles.xml (98%) rename core/{core-ui => ui}/src/main/res/values/themes.xml (100%) rename feature/{feature-apps-picker => apps-picker}/.gitignore (100%) rename feature/{feature-apps-picker => apps-picker}/build.gradle.kts (100%) rename feature/{feature-apps-picker => apps-picker}/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt (100%) rename feature/{feature-apps-picker => apps-picker}/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt (100%) rename feature/{feature-apps-picker => apps-picker}/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt (100%) rename feature/{feature-apps-picker => apps-picker}/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt (100%) rename feature/{feature-apps-picker => apps-picker}/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt (100%) rename feature/{feature-crashes-core => crashes-core}/.gitignore (100%) rename feature/{feature-crashes-core => crashes-core}/build.gradle.kts (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/ControllersModule.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/ANRDetector.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JNICrashDetector.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/BaseCrashDetector.kt (100%) rename feature/{feature-crashes-core => crashes-core}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/DefaultChecker.kt (100%) rename feature/{feature-crashes => crashes}/.gitignore (100%) rename feature/{feature-crashes => crashes}/build.gradle.kts (57%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/adapter/CrashesAdapter.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/AppCrashesViewModelModule.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/CrashDetailsViewModelModule.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/AppCrashesFragment.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/viewholder/CrashViewHolder.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/AppCrashesViewModel.kt (100%) rename feature/{feature-crashes => crashes}/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/dialog_sorting.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/fragment_app_crashes.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/fragment_crash_details.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/fragment_crashes.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/item_crash.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/item_sort.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/layout/placeholder_crashes.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/menu/crash_details_menu.xml (100%) rename feature/{feature-crashes => crashes}/src/main/res/menu/crashes_menu.xml (100%) delete mode 100644 feature/feature-logging/build.gradle.kts rename feature/{feature-filters-core => filters-core}/.gitignore (100%) rename feature/{feature-filters-core => filters-core}/build.gradle.kts (100%) rename feature/{feature-filters-core => filters-core}/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/di/RepositoriesModule.kt (100%) rename feature/{feature-filters-core => filters-core}/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/repository/FiltersRepository.kt (100%) rename feature/{feature-filters => filters}/.gitignore (100%) rename feature/{feature-filters => filters}/build.gradle.kts (57%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/FiltersAdapter.kt (100%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/di/EditFilterViewModelModule.kt (100%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt (100%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/FiltersFragment.kt (100%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/viewholder/FilterViewHolder.kt (100%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt (100%) rename feature/{feature-filters => filters}/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/FiltersViewModel.kt (100%) rename feature/{feature-filters => filters}/src/main/res/layout/fragment_edit_filter.xml (100%) rename feature/{feature-filters => filters}/src/main/res/layout/fragment_filters.xml (100%) rename feature/{feature-filters => filters}/src/main/res/layout/item_filter.xml (100%) rename feature/{feature-filters => filters}/src/main/res/layout/placeholder_filters.xml (100%) rename feature/{feature-filters => filters}/src/main/res/menu/edit_filter_menu.xml (100%) rename feature/{feature-filters => filters}/src/main/res/menu/filters_menu.xml (100%) rename feature/{feature-logging-core => logging-core}/.gitignore (100%) rename feature/{feature-logging-core => logging-core}/build.gradle.kts (100%) rename feature/{feature-logging-core => logging-core}/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/RepositoriesModule.kt (100%) rename feature/{feature-logging-core => logging-core}/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/StoresModule.kt (100%) rename feature/{feature-logging-core => logging-core}/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/model/LogLinesExt.kt (100%) rename feature/{feature-logging-core => logging-core}/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/repository/LoggingRepository.kt (100%) rename feature/{feature-logging-core => logging-core}/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/store/LoggingStore.kt (100%) rename feature/{feature-logging => logging}/.gitignore (100%) create mode 100644 feature/logging/build.gradle.kts rename feature/{feature-logging => logging}/src/main/AndroidManifest.xml (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/di/LogsViewModelModule.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/service/MainActivityPendingIntentProvider.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/ui/dialog/SearchBottomSheet.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsExtendedCopyFragment.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/ui/viewholder/LogViewHolder.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt (100%) rename feature/{feature-logging => logging}/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/UriExt.kt (100%) rename feature/{feature-logging => logging}/src/main/res/layout/fragment_logs.xml (100%) rename feature/{feature-logging => logging}/src/main/res/layout/fragment_logs_extended_copy.xml (100%) rename feature/{feature-logging => logging}/src/main/res/layout/item_log.xml (100%) rename feature/{feature-logging => logging}/src/main/res/layout/placeholder_logs.xml (100%) rename feature/{feature-logging => logging}/src/main/res/layout/sheet_search.xml (100%) rename feature/{feature-logging => logging}/src/main/res/menu/log_menu.xml (100%) rename feature/{feature-logging => logging}/src/main/res/menu/logs_menu.xml (100%) rename feature/{feature-recordings-core => recordings-core}/.gitignore (100%) rename feature/{feature-recordings-core => recordings-core}/build.gradle.kts (69%) rename feature/{feature-recordings-core => recordings-core}/src/main/AndroidManifest.xml (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingController.kt (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/reader/RecordingReader.kt (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/ControllersModule.kt (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/RepositoriesModule.kt (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/receiver/RecordingReceiver.kt (100%) rename feature/{feature-recordings-core => recordings-core}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt (100%) rename feature/{feature-recordings => recordings}/.gitignore (100%) rename feature/{feature-recordings => recordings}/build.gradle.kts (67%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/adapter/RecordingsAdapter.kt (100%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/di/RecordingViewModelModule.kt (100%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt (100%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/fragment/RecordingsFragment.kt (100%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/viewholder/RecordingViewHolder.kt (100%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt (100%) rename feature/{feature-recordings => recordings}/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt (100%) rename feature/{feature-recordings => recordings}/src/main/res/layout/fragment_recordings.xml (100%) rename feature/{feature-recordings => recordings}/src/main/res/layout/item_recording.xml (100%) rename feature/{feature-recordings => recordings}/src/main/res/layout/placeholder_recordings.xml (100%) rename feature/{feature-recordings => recordings}/src/main/res/layout/sheet_recording.xml (100%) rename feature/{feature-recordings => recordings}/src/main/res/menu/recordings_menu.xml (100%) rename feature/{feature-settings => settings}/.gitignore (100%) rename feature/{feature-settings => settings}/build.gradle.kts (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/IntArrayExt.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/LoggingServiceDelegate.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsCrashesFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsLinksFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsMenuFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt (100%) rename feature/{feature-settings => settings}/src/main/res/layout/preference_material_switch.xml (100%) rename feature/{feature-settings => settings}/src/main/res/layout/preference_warning.xml (100%) rename feature/{feature-settings => settings}/src/main/res/values/ids.xml (100%) rename feature/{feature-settings => settings}/src/main/res/xml/settings_crashes.xml (100%) rename feature/{feature-settings => settings}/src/main/res/xml/settings_links.xml (100%) rename feature/{feature-settings => settings}/src/main/res/xml/settings_menu.xml (100%) rename feature/{feature-settings => settings}/src/main/res/xml/settings_notifications.xml (100%) rename feature/{feature-settings => settings}/src/main/res/xml/settings_service.xml (100%) rename feature/{feature-settings => settings}/src/main/res/xml/settings_ui.xml (100%) rename feature/{feature-setup => setup}/.gitignore (100%) rename feature/{feature-setup => setup}/build.gradle.kts (100%) rename feature/{feature-setup => setup}/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/SetupFragment.kt (100%) rename feature/{feature-setup => setup}/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt (100%) rename feature/{feature-setup => setup}/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenState.kt (100%) rename feature/{feature-setup => setup}/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt (100%) rename feature/{feature-setup => setup}/src/test/kotlin/com/f0x1d/logfox/setup/compose/SetupScreenContentTest.kt (100%) rename feature/{feature-setup => setup}/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldOpenAdbDialogOnSetupScreenContent.png (100%) rename feature/{feature-setup => setup}/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowAdbDialogOnSetupScreenContent.png (100%) rename feature/{feature-setup => setup}/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png (100%) rename feature/{feature-setup => setup}/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png (100%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 56f194da..6d01f6fd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,29 +15,15 @@ android { } dependencies { - implementation(projects.feature.featureCrashes) - implementation(projects.feature.featureCrashesCore) - implementation(projects.feature.featureFilters) - implementation(projects.feature.featureFiltersCore) - implementation(projects.feature.featureLogging) - implementation(projects.feature.featureLoggingCore) - implementation(projects.feature.featureRecordings) - implementation(projects.feature.featureRecordingsCore) - implementation(projects.feature.featureSettings) - implementation(projects.feature.featureSetup) + implementation(projects.feature.crashes) + implementation(projects.feature.filters) + implementation(projects.feature.logging) + implementation(projects.feature.recordings) + implementation(projects.feature.settings) + implementation(projects.feature.setup) - implementation(libs.insetter) - implementation(libs.bundles.shizuku) implementation(libs.viewpump) - implementation(libs.gson) - implementation(libs.coil) - implementation(libs.glide) - ksp(libs.glide.compiler) - - implementation(libs.androidx.room) - implementation(libs.androidx.room.runtime) - ksp(libs.androidx.room.compiler) implementation(libs.bundles.androidx) implementation(libs.material) diff --git a/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt b/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt index 967cd219..4543fbc5 100644 --- a/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt +++ b/build-logic/convention/src/main/kotlin/extensions/Dependencies.kt @@ -8,17 +8,17 @@ internal fun DependencyHandlerScope.coreDependencies(withCompose: Boolean = true implementation(project(":data")) implementation(project(":strings")) - implementation(project(":core:core-arch")) - implementation(project(":core:core-database")) - implementation(project(":core:core-datetime")) - implementation(project(":core:core-navigation")) - implementation(project(":core:core-preferences")) - implementation(project(":core:core-terminals")) - implementation(project(":core:core-ui")) + implementation(project(":core:arch")) + implementation(project(":core:database")) + implementation(project(":core:datetime")) + implementation(project(":core:navigation")) + implementation(project(":core:preferences")) + implementation(project(":core:terminals")) + implementation(project(":core:ui")) if (withCompose) { - implementation(project(":core:core-ui-compose")) - testImplementation(project(":core:core-tests")) + implementation(project(":core:ui-compose")) + testImplementation(project(":core:tests")) } } diff --git a/core/core-arch/.gitignore b/core/arch/.gitignore similarity index 100% rename from core/core-arch/.gitignore rename to core/arch/.gitignore diff --git a/core/core-arch/build.gradle.kts b/core/arch/build.gradle.kts similarity index 100% rename from core/core-arch/build.gradle.kts rename to core/arch/build.gradle.kts diff --git a/core/core-arch/src/main/AndroidManifest.xml b/core/arch/src/main/AndroidManifest.xml similarity index 100% rename from core/core-arch/src/main/AndroidManifest.xml rename to core/arch/src/main/AndroidManifest.xml diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ContextExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/FileExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/NotificationExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/PendingIntents.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/adapter/BaseListAdapter.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/adapter/BaseListAdapter.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/adapter/BaseListAdapter.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/adapter/BaseListAdapter.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DispatchersModule.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DispatchersModule.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DispatchersModule.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DispatchersModule.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/di/UtilsModule.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/UtilsModule.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/di/UtilsModule.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/UtilsModule.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/io/OutputStreamExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/io/ZipOutputStreamExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/receiver/CopyReceiver.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/BaseRepository.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/BaseRepository.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/BaseRepository.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/BaseRepository.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/DatabaseProxyRepository.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/DatabaseProxyRepository.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/DatabaseProxyRepository.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/repository/DatabaseProxyRepository.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/SnackbarExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/SnackbarExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/SnackbarExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/SnackbarExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/WindowExt.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/WindowExt.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/WindowExt.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/WindowExt.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseActivity.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/activity/BaseViewModelActivity.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/base/SimpleLifecycleOwner.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseBottomSheet.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/dialog/BaseViewModelBottomSheet.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseFragment.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/BaseViewModelFragment.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeFragment.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/fragment/compose/BaseComposeViewModelFragment.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/viewholder/BaseViewHolder.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/viewholder/BaseViewHolder.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/viewholder/BaseViewHolder.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/ui/viewholder/BaseViewHolder.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseStateViewModel.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/BaseViewModel.kt diff --git a/core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt similarity index 100% rename from core/core-arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt rename to core/arch/src/main/kotlin/com/f0x1d/logfox/arch/viewmodel/Event.kt diff --git a/core/core-arch/src/main/res/color/navbar_transparent_background.xml b/core/arch/src/main/res/color/navbar_transparent_background.xml similarity index 100% rename from core/core-arch/src/main/res/color/navbar_transparent_background.xml rename to core/arch/src/main/res/color/navbar_transparent_background.xml diff --git a/core/core-arch/src/main/res/layout/fragment_compose.xml b/core/arch/src/main/res/layout/fragment_compose.xml similarity index 100% rename from core/core-arch/src/main/res/layout/fragment_compose.xml rename to core/arch/src/main/res/layout/fragment_compose.xml diff --git a/core/core-arch/src/main/res/values/colors.xml b/core/arch/src/main/res/values/colors.xml similarity index 100% rename from core/core-arch/src/main/res/values/colors.xml rename to core/arch/src/main/res/values/colors.xml diff --git a/core/core-database/.gitignore b/core/database/.gitignore similarity index 100% rename from core/core-database/.gitignore rename to core/database/.gitignore diff --git a/core/core-database/build.gradle.kts b/core/database/build.gradle.kts similarity index 89% rename from core/core-database/build.gradle.kts rename to core/database/build.gradle.kts index 8cdced3d..83c12ac8 100644 --- a/core/core-database/build.gradle.kts +++ b/core/database/build.gradle.kts @@ -14,7 +14,7 @@ android { } dependencies { - implementation(projects.core.coreArch) + implementation(projects.core.arch) implementation(libs.androidx.room) implementation(libs.androidx.room.runtime) diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/10.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/10.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/10.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/10.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/11.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/11.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/11.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/11.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/12.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/12.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/12.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/12.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/13.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/13.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/13.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/13.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/14.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/14.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/14.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/14.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/15.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/15.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/15.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/15.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/16.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/16.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/16.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/16.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/17.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/7.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/7.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/7.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/7.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/8.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/8.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/8.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/8.json diff --git a/core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/9.json b/core/database/schemas/com.f0x1d.logfox.database.AppDatabase/9.json similarity index 100% rename from core/core-database/schemas/com.f0x1d.logfox.database.AppDatabase/9.json rename to core/database/schemas/com.f0x1d.logfox.database.AppDatabase/9.json diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt similarity index 100% rename from core/core-database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/AppDatabase.kt diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/di/RoomModule.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/di/RoomModule.kt similarity index 100% rename from core/core-database/src/main/kotlin/com/f0x1d/logfox/database/di/RoomModule.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/di/RoomModule.kt diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/AppCrash.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/AppCrash.kt similarity index 100% rename from core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/AppCrash.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/AppCrash.kt diff --git a/core/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 similarity index 100% rename from core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/DisabledApp.kt diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/LogRecording.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/LogRecording.kt similarity index 100% rename from core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/LogRecording.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/LogRecording.kt diff --git a/core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/UserFilter.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/UserFilter.kt similarity index 100% rename from core/core-database/src/main/kotlin/com/f0x1d/logfox/database/entity/UserFilter.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/entity/UserFilter.kt diff --git a/core/core-datetime/.gitignore b/core/datetime/.gitignore similarity index 100% rename from core/core-datetime/.gitignore rename to core/datetime/.gitignore diff --git a/core/core-datetime/build.gradle.kts b/core/datetime/build.gradle.kts similarity index 73% rename from core/core-datetime/build.gradle.kts rename to core/datetime/build.gradle.kts index 09bbe541..6b984442 100644 --- a/core/core-datetime/build.gradle.kts +++ b/core/datetime/build.gradle.kts @@ -6,5 +6,5 @@ plugins { android.namespace = "com.f0x1d.logfox.datetime" dependencies { - implementation(projects.core.corePreferences) + implementation(projects.core.preferences) } diff --git a/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt b/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt similarity index 100% rename from core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt rename to core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt diff --git a/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt b/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt similarity index 100% rename from core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt rename to core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatter.kt diff --git a/core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt b/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt similarity index 100% rename from core/core-datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt rename to core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/DateTimeFormatterModule.kt diff --git a/core/core-navigation/.gitignore b/core/navigation/.gitignore similarity index 100% rename from core/core-navigation/.gitignore rename to core/navigation/.gitignore diff --git a/core/core-navigation/build.gradle.kts b/core/navigation/build.gradle.kts similarity index 100% rename from core/core-navigation/build.gradle.kts rename to core/navigation/build.gradle.kts diff --git a/core/core-navigation/src/main/kotlin/com/f0x1d/logfox/navigation/Navigation.kt b/core/navigation/src/main/kotlin/com/f0x1d/logfox/navigation/Navigation.kt similarity index 100% rename from core/core-navigation/src/main/kotlin/com/f0x1d/logfox/navigation/Navigation.kt rename to core/navigation/src/main/kotlin/com/f0x1d/logfox/navigation/Navigation.kt diff --git a/core/core-navigation/src/main/res/navigation/crashes.xml b/core/navigation/src/main/res/navigation/crashes.xml similarity index 100% rename from core/core-navigation/src/main/res/navigation/crashes.xml rename to core/navigation/src/main/res/navigation/crashes.xml diff --git a/core/core-navigation/src/main/res/navigation/logs.xml b/core/navigation/src/main/res/navigation/logs.xml similarity index 100% rename from core/core-navigation/src/main/res/navigation/logs.xml rename to core/navigation/src/main/res/navigation/logs.xml diff --git a/core/core-navigation/src/main/res/navigation/nav_graph.xml b/core/navigation/src/main/res/navigation/nav_graph.xml similarity index 100% rename from core/core-navigation/src/main/res/navigation/nav_graph.xml rename to core/navigation/src/main/res/navigation/nav_graph.xml diff --git a/core/core-navigation/src/main/res/navigation/recordings.xml b/core/navigation/src/main/res/navigation/recordings.xml similarity index 100% rename from core/core-navigation/src/main/res/navigation/recordings.xml rename to core/navigation/src/main/res/navigation/recordings.xml diff --git a/core/core-navigation/src/main/res/navigation/settings.xml b/core/navigation/src/main/res/navigation/settings.xml similarity index 100% rename from core/core-navigation/src/main/res/navigation/settings.xml rename to core/navigation/src/main/res/navigation/settings.xml diff --git a/core/core-preferences/.gitignore b/core/preferences/.gitignore similarity index 100% rename from core/core-preferences/.gitignore rename to core/preferences/.gitignore diff --git a/core/core-preferences/build.gradle.kts b/core/preferences/build.gradle.kts similarity index 79% rename from core/core-preferences/build.gradle.kts rename to core/preferences/build.gradle.kts index 87d9d013..02384c1a 100644 --- a/core/core-preferences/build.gradle.kts +++ b/core/preferences/build.gradle.kts @@ -6,7 +6,7 @@ plugins { android.namespace = "com.f0x1d.logfox.preferences" dependencies { - implementation(projects.core.coreDatabase) + implementation(projects.core.database) implementation(libs.flow.preferences) } diff --git a/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt b/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt similarity index 100% rename from core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt rename to core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt diff --git a/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/ContextExt.kt b/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/ContextExt.kt similarity index 100% rename from core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/ContextExt.kt rename to core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/ContextExt.kt diff --git a/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/base/BasePreferences.kt b/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/base/BasePreferences.kt similarity index 100% rename from core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/base/BasePreferences.kt rename to core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/base/BasePreferences.kt diff --git a/core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/crashes/CrashesSort.kt b/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/crashes/CrashesSort.kt similarity index 100% rename from core/core-preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/crashes/CrashesSort.kt rename to core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/crashes/CrashesSort.kt diff --git a/core/core-terminals/.gitignore b/core/terminals/.gitignore similarity index 100% rename from core/core-terminals/.gitignore rename to core/terminals/.gitignore diff --git a/core/core-terminals/build.gradle.kts b/core/terminals/build.gradle.kts similarity index 85% rename from core/core-terminals/build.gradle.kts rename to core/terminals/build.gradle.kts index e06d37b9..1b4c2aae 100644 --- a/core/core-terminals/build.gradle.kts +++ b/core/terminals/build.gradle.kts @@ -10,7 +10,7 @@ android { } dependencies { - implementation(projects.core.coreArch) + implementation(projects.core.arch) implementation(libs.libsu) implementation(libs.bundles.shizuku) diff --git a/core/core-terminals/src/main/AndroidManifest.xml b/core/terminals/src/main/AndroidManifest.xml similarity index 100% rename from core/core-terminals/src/main/AndroidManifest.xml rename to core/terminals/src/main/AndroidManifest.xml diff --git a/core/core-terminals/src/main/aidl/com/f0x1d/logfox/IUserService.aidl b/core/terminals/src/main/aidl/com/f0x1d/logfox/IUserService.aidl similarity index 100% rename from core/core-terminals/src/main/aidl/com/f0x1d/logfox/IUserService.aidl rename to core/terminals/src/main/aidl/com/f0x1d/logfox/IUserService.aidl diff --git a/core/core-terminals/src/main/aidl/com/f0x1d/logfox/model/terminal/TerminalResult.aidl b/core/terminals/src/main/aidl/com/f0x1d/logfox/model/terminal/TerminalResult.aidl similarity index 100% rename from core/core-terminals/src/main/aidl/com/f0x1d/logfox/model/terminal/TerminalResult.aidl rename to core/terminals/src/main/aidl/com/f0x1d/logfox/model/terminal/TerminalResult.aidl diff --git a/core/core-terminals/src/main/kotlin/com/f0x1d/logfox/di/TerminalsModule.kt b/core/terminals/src/main/kotlin/com/f0x1d/logfox/di/TerminalsModule.kt similarity index 100% rename from core/core-terminals/src/main/kotlin/com/f0x1d/logfox/di/TerminalsModule.kt rename to core/terminals/src/main/kotlin/com/f0x1d/logfox/di/TerminalsModule.kt diff --git a/core/core-terminals/src/main/kotlin/com/f0x1d/logfox/service/UserService.kt b/core/terminals/src/main/kotlin/com/f0x1d/logfox/service/UserService.kt similarity index 100% rename from core/core-terminals/src/main/kotlin/com/f0x1d/logfox/service/UserService.kt rename to core/terminals/src/main/kotlin/com/f0x1d/logfox/service/UserService.kt diff --git a/core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/DefaultTerminal.kt b/core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/DefaultTerminal.kt similarity index 100% rename from core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/DefaultTerminal.kt rename to core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/DefaultTerminal.kt diff --git a/core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/RootTerminal.kt b/core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/RootTerminal.kt similarity index 100% rename from core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/RootTerminal.kt rename to core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/RootTerminal.kt diff --git a/core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/ShizukuTerminal.kt b/core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/ShizukuTerminal.kt similarity index 100% rename from core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/ShizukuTerminal.kt rename to core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/ShizukuTerminal.kt diff --git a/core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/base/Terminal.kt b/core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/base/Terminal.kt similarity index 100% rename from core/core-terminals/src/main/kotlin/com/f0x1d/logfox/terminals/base/Terminal.kt rename to core/terminals/src/main/kotlin/com/f0x1d/logfox/terminals/base/Terminal.kt diff --git a/core/core-terminals/src/main/res/values-it/strings.xml b/core/terminals/src/main/res/values-it/strings.xml similarity index 100% rename from core/core-terminals/src/main/res/values-it/strings.xml rename to core/terminals/src/main/res/values-it/strings.xml diff --git a/core/core-terminals/src/main/res/values-pt-rBR/strings.xml b/core/terminals/src/main/res/values-pt-rBR/strings.xml similarity index 100% rename from core/core-terminals/src/main/res/values-pt-rBR/strings.xml rename to core/terminals/src/main/res/values-pt-rBR/strings.xml diff --git a/core/core-terminals/src/main/res/values-ru/strings.xml b/core/terminals/src/main/res/values-ru/strings.xml similarity index 100% rename from core/core-terminals/src/main/res/values-ru/strings.xml rename to core/terminals/src/main/res/values-ru/strings.xml diff --git a/core/core-terminals/src/main/res/values-tr/strings.xml b/core/terminals/src/main/res/values-tr/strings.xml similarity index 100% rename from core/core-terminals/src/main/res/values-tr/strings.xml rename to core/terminals/src/main/res/values-tr/strings.xml diff --git a/core/core-terminals/src/main/res/values-zh-rCN/strings.xml b/core/terminals/src/main/res/values-zh-rCN/strings.xml similarity index 100% rename from core/core-terminals/src/main/res/values-zh-rCN/strings.xml rename to core/terminals/src/main/res/values-zh-rCN/strings.xml diff --git a/core/core-terminals/src/main/res/values/strings.xml b/core/terminals/src/main/res/values/strings.xml similarity index 100% rename from core/core-terminals/src/main/res/values/strings.xml rename to core/terminals/src/main/res/values/strings.xml diff --git a/core/core-tests/.gitignore b/core/tests/.gitignore similarity index 100% rename from core/core-tests/.gitignore rename to core/tests/.gitignore diff --git a/core/core-tests/build.gradle.kts b/core/tests/build.gradle.kts similarity index 100% rename from core/core-tests/build.gradle.kts rename to core/tests/build.gradle.kts diff --git a/core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt b/core/tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt similarity index 100% rename from core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt rename to core/tests/src/main/kotlin/com/f0x1d/logfox/core/tests/ScreenshotTest.kt diff --git a/core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/compose/SemanticsNodeInteractionsProviderExt.kt b/core/tests/src/main/kotlin/com/f0x1d/logfox/core/tests/compose/SemanticsNodeInteractionsProviderExt.kt similarity index 100% rename from core/core-tests/src/main/kotlin/com/f0x1d/logfox/core/tests/compose/SemanticsNodeInteractionsProviderExt.kt rename to core/tests/src/main/kotlin/com/f0x1d/logfox/core/tests/compose/SemanticsNodeInteractionsProviderExt.kt diff --git a/core/core-ui-compose/.gitignore b/core/ui-compose/.gitignore similarity index 100% rename from core/core-ui-compose/.gitignore rename to core/ui-compose/.gitignore diff --git a/core/core-ui-compose/build.gradle.kts b/core/ui-compose/build.gradle.kts similarity index 77% rename from core/core-ui-compose/build.gradle.kts rename to core/ui-compose/build.gradle.kts index cdf32dff..1a171d32 100644 --- a/core/core-ui-compose/build.gradle.kts +++ b/core/ui-compose/build.gradle.kts @@ -6,5 +6,5 @@ plugins { android.namespace = "com.f0x1d.logfox.ui.compose" dependencies { - implementation(projects.core.coreUi) + implementation(projects.core.ui) } diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/NavigationBackButton.kt diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/button/RichButton.kt diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/component/search/TopSearchBar.kt diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/preview/DayNightPreview.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/preview/DayNightPreview.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/preview/DayNightPreview.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/preview/DayNightPreview.kt diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Color.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Color.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Color.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Color.kt diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Theme.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Theme.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Theme.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Theme.kt diff --git a/core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Type.kt b/core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Type.kt similarity index 100% rename from core/core-ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Type.kt rename to core/ui-compose/src/main/kotlin/com/f0x1d/logfox/ui/compose/theme/Type.kt diff --git a/core/core-ui-compose/src/main/res/values/font_certs.xml b/core/ui-compose/src/main/res/values/font_certs.xml similarity index 100% rename from core/core-ui-compose/src/main/res/values/font_certs.xml rename to core/ui-compose/src/main/res/values/font_certs.xml diff --git a/core/core-ui/.gitignore b/core/ui/.gitignore similarity index 100% rename from core/core-ui/.gitignore rename to core/ui/.gitignore diff --git a/core/core-ui/build.gradle.kts b/core/ui/build.gradle.kts similarity index 73% rename from core/core-ui/build.gradle.kts rename to core/ui/build.gradle.kts index d904a199..8a5682c3 100644 --- a/core/core-ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -6,8 +6,8 @@ plugins { android.namespace = "com.f0x1d.logfox.ui" dependencies { - implementation(projects.core.coreArch) - implementation(projects.core.corePreferences) + implementation(projects.core.arch) + implementation(projects.core.preferences) implementation(libs.insetter) implementation(libs.viewpump) diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/Icons.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/Icons.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/Icons.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/Icons.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/density/PxExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/density/PxExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/density/PxExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/density/PxExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/di/ViewPumpModule.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/di/ViewPumpModule.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/di/ViewPumpModule.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/di/ViewPumpModule.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/dialog/AreYouSureDialogExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/dialog/AreYouSureDialogExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/dialog/AreYouSureDialogExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/dialog/AreYouSureDialogExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconDataFetcher.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconDataFetcher.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconDataFetcher.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconDataFetcher.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconGlideModule.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconGlideModule.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconGlideModule.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconGlideModule.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoader.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoader.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoader.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoader.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoaderFactory.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoaderFactory.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoaderFactory.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/glide/icon/IconModelLoaderFactory.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/interceptor/FontsInterceptor.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/interceptor/FontsInterceptor.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/interceptor/FontsInterceptor.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/interceptor/FontsInterceptor.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomApplyInsetsNavigationRailView.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomApplyInsetsNavigationRailView.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomApplyInsetsNavigationRailView.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomApplyInsetsNavigationRailView.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomNestedScrollView.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomNestedScrollView.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomNestedScrollView.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/CustomNestedScrollView.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/FABExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/FABExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/FABExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/FABExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ImageViewExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ImageViewExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ImageViewExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ImageViewExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/MenuExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/MenuExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/MenuExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/MenuExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/OnlyUserCheckedChangeListener.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/OnlyUserCheckedChangeListener.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/OnlyUserCheckedChangeListener.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/OnlyUserCheckedChangeListener.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/PreferenceExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ToolbarExt.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ToolbarExt.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ToolbarExt.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/ToolbarExt.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelExtensions.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelExtensions.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelExtensions.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelExtensions.kt diff --git a/core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelView.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelView.kt similarity index 100% rename from core/core-ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelView.kt rename to core/ui/src/main/kotlin/com/f0x1d/logfox/ui/view/loglevel/LogLevelView.kt diff --git a/core/core-ui/src/main/res/color/item_log_background_ripple.xml b/core/ui/src/main/res/color/item_log_background_ripple.xml similarity index 100% rename from core/core-ui/src/main/res/color/item_log_background_ripple.xml rename to core/ui/src/main/res/color/item_log_background_ripple.xml diff --git a/core/core-ui/src/main/res/drawable-ldrtl/item_log_level_background.xml b/core/ui/src/main/res/drawable-ldrtl/item_log_level_background.xml similarity index 100% rename from core/core-ui/src/main/res/drawable-ldrtl/item_log_level_background.xml rename to core/ui/src/main/res/drawable-ldrtl/item_log_level_background.xml diff --git a/core/core-ui/src/main/res/drawable/ic_adb.xml b/core/ui/src/main/res/drawable/ic_adb.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_adb.xml rename to core/ui/src/main/res/drawable/ic_adb.xml diff --git a/core/core-ui/src/main/res/drawable/ic_add.xml b/core/ui/src/main/res/drawable/ic_add.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_add.xml rename to core/ui/src/main/res/drawable/ic_add.xml diff --git a/core/core-ui/src/main/res/drawable/ic_add_link.xml b/core/ui/src/main/res/drawable/ic_add_link.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_add_link.xml rename to core/ui/src/main/res/drawable/ic_add_link.xml diff --git a/core/core-ui/src/main/res/drawable/ic_alert.xml b/core/ui/src/main/res/drawable/ic_alert.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_alert.xml rename to core/ui/src/main/res/drawable/ic_alert.xml diff --git a/core/core-ui/src/main/res/drawable/ic_android.xml b/core/ui/src/main/res/drawable/ic_android.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_android.xml rename to core/ui/src/main/res/drawable/ic_android.xml diff --git a/core/core-ui/src/main/res/drawable/ic_android_anim.xml b/core/ui/src/main/res/drawable/ic_android_anim.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_android_anim.xml rename to core/ui/src/main/res/drawable/ic_android_anim.xml diff --git a/core/core-ui/src/main/res/drawable/ic_android_avd.xml b/core/ui/src/main/res/drawable/ic_android_avd.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_android_avd.xml rename to core/ui/src/main/res/drawable/ic_android_avd.xml diff --git a/core/core-ui/src/main/res/drawable/ic_archive.xml b/core/ui/src/main/res/drawable/ic_archive.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_archive.xml rename to core/ui/src/main/res/drawable/ic_archive.xml diff --git a/core/core-ui/src/main/res/drawable/ic_arrow_back.xml b/core/ui/src/main/res/drawable/ic_arrow_back.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_arrow_back.xml rename to core/ui/src/main/res/drawable/ic_arrow_back.xml diff --git a/core/core-ui/src/main/res/drawable/ic_arrow_drop_down.xml b/core/ui/src/main/res/drawable/ic_arrow_drop_down.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_arrow_drop_down.xml rename to core/ui/src/main/res/drawable/ic_arrow_drop_down.xml diff --git a/core/core-ui/src/main/res/drawable/ic_block.xml b/core/ui/src/main/res/drawable/ic_block.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_block.xml rename to core/ui/src/main/res/drawable/ic_block.xml diff --git a/core/core-ui/src/main/res/drawable/ic_bug.xml b/core/ui/src/main/res/drawable/ic_bug.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_bug.xml rename to core/ui/src/main/res/drawable/ic_bug.xml diff --git a/core/core-ui/src/main/res/drawable/ic_bug_anim.xml b/core/ui/src/main/res/drawable/ic_bug_anim.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_bug_anim.xml rename to core/ui/src/main/res/drawable/ic_bug_anim.xml diff --git a/core/core-ui/src/main/res/drawable/ic_bug_avd.xml b/core/ui/src/main/res/drawable/ic_bug_avd.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_bug_avd.xml rename to core/ui/src/main/res/drawable/ic_bug_avd.xml diff --git a/core/core-ui/src/main/res/drawable/ic_bug_notification.xml b/core/ui/src/main/res/drawable/ic_bug_notification.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_bug_notification.xml rename to core/ui/src/main/res/drawable/ic_bug_notification.xml diff --git a/core/core-ui/src/main/res/drawable/ic_checklist.xml b/core/ui/src/main/res/drawable/ic_checklist.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_checklist.xml rename to core/ui/src/main/res/drawable/ic_checklist.xml diff --git a/core/core-ui/src/main/res/drawable/ic_clear.xml b/core/ui/src/main/res/drawable/ic_clear.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_clear.xml rename to core/ui/src/main/res/drawable/ic_clear.xml diff --git a/core/core-ui/src/main/res/drawable/ic_clear_all.xml b/core/ui/src/main/res/drawable/ic_clear_all.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_clear_all.xml rename to core/ui/src/main/res/drawable/ic_clear_all.xml diff --git a/core/core-ui/src/main/res/drawable/ic_copy.xml b/core/ui/src/main/res/drawable/ic_copy.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_copy.xml rename to core/ui/src/main/res/drawable/ic_copy.xml diff --git a/core/core-ui/src/main/res/drawable/ic_delete.xml b/core/ui/src/main/res/drawable/ic_delete.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_delete.xml rename to core/ui/src/main/res/drawable/ic_delete.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_adb.xml b/core/ui/src/main/res/drawable/ic_dialog_adb.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_adb.xml rename to core/ui/src/main/res/drawable/ic_dialog_adb.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_date_format.xml b/core/ui/src/main/res/drawable/ic_dialog_date_format.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_date_format.xml rename to core/ui/src/main/res/drawable/ic_dialog_date_format.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_eye.xml b/core/ui/src/main/res/drawable/ic_dialog_eye.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_eye.xml rename to core/ui/src/main/res/drawable/ic_dialog_eye.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_list.xml b/core/ui/src/main/res/drawable/ic_dialog_list.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_list.xml rename to core/ui/src/main/res/drawable/ic_dialog_list.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_notification_important.xml b/core/ui/src/main/res/drawable/ic_dialog_notification_important.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_notification_important.xml rename to core/ui/src/main/res/drawable/ic_dialog_notification_important.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_terminal.xml b/core/ui/src/main/res/drawable/ic_dialog_terminal.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_terminal.xml rename to core/ui/src/main/res/drawable/ic_dialog_terminal.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_text_fields.xml b/core/ui/src/main/res/drawable/ic_dialog_text_fields.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_text_fields.xml rename to core/ui/src/main/res/drawable/ic_dialog_text_fields.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_theme.xml b/core/ui/src/main/res/drawable/ic_dialog_theme.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_theme.xml rename to core/ui/src/main/res/drawable/ic_dialog_theme.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_time_format.xml b/core/ui/src/main/res/drawable/ic_dialog_time_format.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_time_format.xml rename to core/ui/src/main/res/drawable/ic_dialog_time_format.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_timer.xml b/core/ui/src/main/res/drawable/ic_dialog_timer.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_timer.xml rename to core/ui/src/main/res/drawable/ic_dialog_timer.xml diff --git a/core/core-ui/src/main/res/drawable/ic_dialog_warning.xml b/core/ui/src/main/res/drawable/ic_dialog_warning.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_dialog_warning.xml rename to core/ui/src/main/res/drawable/ic_dialog_warning.xml diff --git a/core/core-ui/src/main/res/drawable/ic_export.xml b/core/ui/src/main/res/drawable/ic_export.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_export.xml rename to core/ui/src/main/res/drawable/ic_export.xml diff --git a/core/core-ui/src/main/res/drawable/ic_eye.xml b/core/ui/src/main/res/drawable/ic_eye.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_eye.xml rename to core/ui/src/main/res/drawable/ic_eye.xml diff --git a/core/core-ui/src/main/res/drawable/ic_filter.xml b/core/ui/src/main/res/drawable/ic_filter.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_filter.xml rename to core/ui/src/main/res/drawable/ic_filter.xml diff --git a/core/core-ui/src/main/res/drawable/ic_info.xml b/core/ui/src/main/res/drawable/ic_info.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_info.xml rename to core/ui/src/main/res/drawable/ic_info.xml diff --git a/core/core-ui/src/main/res/drawable/ic_launcher_foreground.xml b/core/ui/src/main/res/drawable/ic_launcher_foreground.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_launcher_foreground.xml rename to core/ui/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/core/core-ui/src/main/res/drawable/ic_logfox.xml b/core/ui/src/main/res/drawable/ic_logfox.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_logfox.xml rename to core/ui/src/main/res/drawable/ic_logfox.xml diff --git a/core/core-ui/src/main/res/drawable/ic_logfox_anim.xml b/core/ui/src/main/res/drawable/ic_logfox_anim.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_logfox_anim.xml rename to core/ui/src/main/res/drawable/ic_logfox_anim.xml diff --git a/core/core-ui/src/main/res/drawable/ic_logfox_avd.xml b/core/ui/src/main/res/drawable/ic_logfox_avd.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_logfox_avd.xml rename to core/ui/src/main/res/drawable/ic_logfox_avd.xml diff --git a/core/core-ui/src/main/res/drawable/ic_notifications.xml b/core/ui/src/main/res/drawable/ic_notifications.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_notifications.xml rename to core/ui/src/main/res/drawable/ic_notifications.xml diff --git a/core/core-ui/src/main/res/drawable/ic_pause.xml b/core/ui/src/main/res/drawable/ic_pause.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_pause.xml rename to core/ui/src/main/res/drawable/ic_pause.xml diff --git a/core/core-ui/src/main/res/drawable/ic_play.xml b/core/ui/src/main/res/drawable/ic_play.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_play.xml rename to core/ui/src/main/res/drawable/ic_play.xml diff --git a/core/core-ui/src/main/res/drawable/ic_recording.xml b/core/ui/src/main/res/drawable/ic_recording.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_recording.xml rename to core/ui/src/main/res/drawable/ic_recording.xml diff --git a/core/core-ui/src/main/res/drawable/ic_recording_anim.xml b/core/ui/src/main/res/drawable/ic_recording_anim.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_recording_anim.xml rename to core/ui/src/main/res/drawable/ic_recording_anim.xml diff --git a/core/core-ui/src/main/res/drawable/ic_recording_avd.xml b/core/ui/src/main/res/drawable/ic_recording_avd.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_recording_avd.xml rename to core/ui/src/main/res/drawable/ic_recording_avd.xml diff --git a/core/core-ui/src/main/res/drawable/ic_recording_notification.xml b/core/ui/src/main/res/drawable/ic_recording_notification.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_recording_notification.xml rename to core/ui/src/main/res/drawable/ic_recording_notification.xml diff --git a/core/core-ui/src/main/res/drawable/ic_recording_play_notification.xml b/core/ui/src/main/res/drawable/ic_recording_play_notification.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_recording_play_notification.xml rename to core/ui/src/main/res/drawable/ic_recording_play_notification.xml diff --git a/core/core-ui/src/main/res/drawable/ic_save.xml b/core/ui/src/main/res/drawable/ic_save.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_save.xml rename to core/ui/src/main/res/drawable/ic_save.xml diff --git a/core/core-ui/src/main/res/drawable/ic_search.xml b/core/ui/src/main/res/drawable/ic_search.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_search.xml rename to core/ui/src/main/res/drawable/ic_search.xml diff --git a/core/core-ui/src/main/res/drawable/ic_select.xml b/core/ui/src/main/res/drawable/ic_select.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_select.xml rename to core/ui/src/main/res/drawable/ic_select.xml diff --git a/core/core-ui/src/main/res/drawable/ic_select_all.xml b/core/ui/src/main/res/drawable/ic_select_all.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_select_all.xml rename to core/ui/src/main/res/drawable/ic_select_all.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings.xml b/core/ui/src/main/res/drawable/ic_settings.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings.xml rename to core/ui/src/main/res/drawable/ic_settings.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_anim.xml b/core/ui/src/main/res/drawable/ic_settings_anim.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_anim.xml rename to core/ui/src/main/res/drawable/ic_settings_anim.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_avd.xml b/core/ui/src/main/res/drawable/ic_settings_avd.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_avd.xml rename to core/ui/src/main/res/drawable/ic_settings_avd.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_code.xml b/core/ui/src/main/res/drawable/ic_settings_code.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_code.xml rename to core/ui/src/main/res/drawable/ic_settings_code.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_crashes.xml b/core/ui/src/main/res/drawable/ic_settings_crashes.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_crashes.xml rename to core/ui/src/main/res/drawable/ic_settings_crashes.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_handyman.xml b/core/ui/src/main/res/drawable/ic_settings_handyman.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_handyman.xml rename to core/ui/src/main/res/drawable/ic_settings_handyman.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_info.xml b/core/ui/src/main/res/drawable/ic_settings_info.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_info.xml rename to core/ui/src/main/res/drawable/ic_settings_info.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_notifications.xml b/core/ui/src/main/res/drawable/ic_settings_notifications.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_notifications.xml rename to core/ui/src/main/res/drawable/ic_settings_notifications.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_person.xml b/core/ui/src/main/res/drawable/ic_settings_person.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_person.xml rename to core/ui/src/main/res/drawable/ic_settings_person.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_releases.xml b/core/ui/src/main/res/drawable/ic_settings_releases.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_releases.xml rename to core/ui/src/main/res/drawable/ic_settings_releases.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_service.xml b/core/ui/src/main/res/drawable/ic_settings_service.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_service.xml rename to core/ui/src/main/res/drawable/ic_settings_service.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_ui.xml b/core/ui/src/main/res/drawable/ic_settings_ui.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_ui.xml rename to core/ui/src/main/res/drawable/ic_settings_ui.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_users.xml b/core/ui/src/main/res/drawable/ic_settings_users.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_users.xml rename to core/ui/src/main/res/drawable/ic_settings_users.xml diff --git a/core/core-ui/src/main/res/drawable/ic_settings_warning.xml b/core/ui/src/main/res/drawable/ic_settings_warning.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_settings_warning.xml rename to core/ui/src/main/res/drawable/ic_settings_warning.xml diff --git a/core/core-ui/src/main/res/drawable/ic_share.xml b/core/ui/src/main/res/drawable/ic_share.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_share.xml rename to core/ui/src/main/res/drawable/ic_share.xml diff --git a/core/core-ui/src/main/res/drawable/ic_sort.xml b/core/ui/src/main/res/drawable/ic_sort.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_sort.xml rename to core/ui/src/main/res/drawable/ic_sort.xml diff --git a/core/core-ui/src/main/res/drawable/ic_square_root.xml b/core/ui/src/main/res/drawable/ic_square_root.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_square_root.xml rename to core/ui/src/main/res/drawable/ic_square_root.xml diff --git a/core/core-ui/src/main/res/drawable/ic_stop.xml b/core/ui/src/main/res/drawable/ic_stop.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_stop.xml rename to core/ui/src/main/res/drawable/ic_stop.xml diff --git a/core/core-ui/src/main/res/drawable/ic_terminal.xml b/core/ui/src/main/res/drawable/ic_terminal.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/ic_terminal.xml rename to core/ui/src/main/res/drawable/ic_terminal.xml diff --git a/core/core-ui/src/main/res/drawable/item_log_background.xml b/core/ui/src/main/res/drawable/item_log_background.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/item_log_background.xml rename to core/ui/src/main/res/drawable/item_log_background.xml diff --git a/core/core-ui/src/main/res/drawable/item_log_level_background.xml b/core/ui/src/main/res/drawable/item_log_level_background.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/item_log_level_background.xml rename to core/ui/src/main/res/drawable/item_log_level_background.xml diff --git a/core/core-ui/src/main/res/drawable/placeholder_icon_background.xml b/core/ui/src/main/res/drawable/placeholder_icon_background.xml similarity index 100% rename from core/core-ui/src/main/res/drawable/placeholder_icon_background.xml rename to core/ui/src/main/res/drawable/placeholder_icon_background.xml diff --git a/core/core-ui/src/main/res/font/google_sans.ttf b/core/ui/src/main/res/font/google_sans.ttf similarity index 100% rename from core/core-ui/src/main/res/font/google_sans.ttf rename to core/ui/src/main/res/font/google_sans.ttf diff --git a/core/core-ui/src/main/res/font/google_sans_medium.ttf b/core/ui/src/main/res/font/google_sans_medium.ttf similarity index 100% rename from core/core-ui/src/main/res/font/google_sans_medium.ttf rename to core/ui/src/main/res/font/google_sans_medium.ttf diff --git a/core/core-ui/src/main/res/layout/dialog_text.xml b/core/ui/src/main/res/layout/dialog_text.xml similarity index 100% rename from core/core-ui/src/main/res/layout/dialog_text.xml rename to core/ui/src/main/res/layout/dialog_text.xml diff --git a/core/core-ui/src/main/res/layout/fragment_settings.xml b/core/ui/src/main/res/layout/fragment_settings.xml similarity index 100% rename from core/core-ui/src/main/res/layout/fragment_settings.xml rename to core/ui/src/main/res/layout/fragment_settings.xml diff --git a/core/core-ui/src/main/res/values-night/colors.xml b/core/ui/src/main/res/values-night/colors.xml similarity index 100% rename from core/core-ui/src/main/res/values-night/colors.xml rename to core/ui/src/main/res/values-night/colors.xml diff --git a/core/core-ui/src/main/res/values/colors.xml b/core/ui/src/main/res/values/colors.xml similarity index 100% rename from core/core-ui/src/main/res/values/colors.xml rename to core/ui/src/main/res/values/colors.xml diff --git a/core/core-ui/src/main/res/values/ids.xml b/core/ui/src/main/res/values/ids.xml similarity index 100% rename from core/core-ui/src/main/res/values/ids.xml rename to core/ui/src/main/res/values/ids.xml diff --git a/core/core-ui/src/main/res/values/styles.xml b/core/ui/src/main/res/values/styles.xml similarity index 98% rename from core/core-ui/src/main/res/values/styles.xml rename to core/ui/src/main/res/values/styles.xml index 7d32dee7..9f87fe53 100644 --- a/core/core-ui/src/main/res/values/styles.xml +++ b/core/ui/src/main/res/values/styles.xml @@ -66,5 +66,6 @@ diff --git a/core/core-ui/src/main/res/values/themes.xml b/core/ui/src/main/res/values/themes.xml similarity index 100% rename from core/core-ui/src/main/res/values/themes.xml rename to core/ui/src/main/res/values/themes.xml diff --git a/feature/feature-apps-picker/.gitignore b/feature/apps-picker/.gitignore similarity index 100% rename from feature/feature-apps-picker/.gitignore rename to feature/apps-picker/.gitignore diff --git a/feature/feature-apps-picker/build.gradle.kts b/feature/apps-picker/build.gradle.kts similarity index 100% rename from feature/feature-apps-picker/build.gradle.kts rename to feature/apps-picker/build.gradle.kts diff --git a/feature/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 similarity index 100% rename from feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt rename to feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/AppsPickerFragment.kt diff --git a/feature/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 similarity index 100% rename from feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt rename to feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenContent.kt diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt similarity index 100% rename from feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt rename to feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt diff --git a/feature/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 similarity index 100% rename from feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt rename to feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerResultHandler.kt diff --git a/feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt similarity index 100% rename from feature/feature-apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt rename to feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/viewmodel/AppsPickerViewModel.kt diff --git a/feature/feature-crashes-core/.gitignore b/feature/crashes-core/.gitignore similarity index 100% rename from feature/feature-crashes-core/.gitignore rename to feature/crashes-core/.gitignore diff --git a/feature/feature-crashes-core/build.gradle.kts b/feature/crashes-core/build.gradle.kts similarity index 100% rename from feature/feature-crashes-core/build.gradle.kts rename to feature/crashes-core/build.gradle.kts diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesController.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/controller/CrashesNotificationsController.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/ControllersModule.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/ControllersModule.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/ControllersModule.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/ControllersModule.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/di/RepositoriesModule.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/CrashesRepository.kt diff --git a/feature/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 similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/DisabledAppsRepository.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/ANRDetector.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/ANRDetector.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/ANRDetector.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/ANRDetector.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JNICrashDetector.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JNICrashDetector.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JNICrashDetector.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JNICrashDetector.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt index 2498b1f6..563fc52d 100644 --- a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt +++ b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/JavaCrashDetector.kt @@ -3,8 +3,8 @@ package com.f0x1d.logfox.feature.crashes.core.repository.reader import android.content.Context import com.f0x1d.logfox.database.entity.AppCrash import com.f0x1d.logfox.database.entity.CrashType -import com.f0x1d.logfox.model.logline.LogLine import com.f0x1d.logfox.feature.crashes.core.repository.reader.base.BaseCrashDetector +import com.f0x1d.logfox.model.logline.LogLine internal class JavaCrashDetector( context: Context, diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/BaseCrashDetector.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/BaseCrashDetector.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/BaseCrashDetector.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/BaseCrashDetector.kt diff --git a/feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/DefaultChecker.kt b/feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/DefaultChecker.kt similarity index 100% rename from feature/feature-crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/DefaultChecker.kt rename to feature/crashes-core/src/main/kotlin/com/f0x1d/logfox/feature/crashes/core/repository/reader/base/DefaultChecker.kt diff --git a/feature/feature-crashes/.gitignore b/feature/crashes/.gitignore similarity index 100% rename from feature/feature-crashes/.gitignore rename to feature/crashes/.gitignore diff --git a/feature/feature-crashes/build.gradle.kts b/feature/crashes/build.gradle.kts similarity index 57% rename from feature/feature-crashes/build.gradle.kts rename to feature/crashes/build.gradle.kts index b4de008d..520137cc 100644 --- a/feature/feature-crashes/build.gradle.kts +++ b/feature/crashes/build.gradle.kts @@ -5,8 +5,8 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.crashes" dependencies { - implementation(projects.feature.featureAppsPicker) - implementation(projects.feature.featureCrashesCore) + implementation(projects.feature.appsPicker) + implementation(projects.feature.crashesCore) implementation(libs.glide) } diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/adapter/CrashesAdapter.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/adapter/CrashesAdapter.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/adapter/CrashesAdapter.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/adapter/CrashesAdapter.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/AppCrashesViewModelModule.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/AppCrashesViewModelModule.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/AppCrashesViewModelModule.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/AppCrashesViewModelModule.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/CrashDetailsViewModelModule.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/CrashDetailsViewModelModule.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/CrashDetailsViewModelModule.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/di/CrashDetailsViewModelModule.kt diff --git a/feature/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 similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/CrashDetailsFragment.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/AppCrashesFragment.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/AppCrashesFragment.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/AppCrashesFragment.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/AppCrashesFragment.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/fragment/list/CrashesFragment.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/viewholder/CrashViewHolder.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/viewholder/CrashViewHolder.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/viewholder/CrashViewHolder.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/ui/viewholder/CrashViewHolder.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/CrashDetailsViewModel.kt diff --git a/feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/AppCrashesViewModel.kt b/feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/AppCrashesViewModel.kt similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/AppCrashesViewModel.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/AppCrashesViewModel.kt diff --git a/feature/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 similarity index 100% rename from feature/feature-crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt rename to feature/crashes/src/main/kotlin/com/f0x1d/logfox/feature/crashes/viewmodel/list/CrashesViewModel.kt diff --git a/feature/feature-crashes/src/main/res/layout/dialog_sorting.xml b/feature/crashes/src/main/res/layout/dialog_sorting.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/dialog_sorting.xml rename to feature/crashes/src/main/res/layout/dialog_sorting.xml diff --git a/feature/feature-crashes/src/main/res/layout/fragment_app_crashes.xml b/feature/crashes/src/main/res/layout/fragment_app_crashes.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/fragment_app_crashes.xml rename to feature/crashes/src/main/res/layout/fragment_app_crashes.xml diff --git a/feature/feature-crashes/src/main/res/layout/fragment_crash_details.xml b/feature/crashes/src/main/res/layout/fragment_crash_details.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/fragment_crash_details.xml rename to feature/crashes/src/main/res/layout/fragment_crash_details.xml diff --git a/feature/feature-crashes/src/main/res/layout/fragment_crashes.xml b/feature/crashes/src/main/res/layout/fragment_crashes.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/fragment_crashes.xml rename to feature/crashes/src/main/res/layout/fragment_crashes.xml diff --git a/feature/feature-crashes/src/main/res/layout/item_crash.xml b/feature/crashes/src/main/res/layout/item_crash.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/item_crash.xml rename to feature/crashes/src/main/res/layout/item_crash.xml diff --git a/feature/feature-crashes/src/main/res/layout/item_sort.xml b/feature/crashes/src/main/res/layout/item_sort.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/item_sort.xml rename to feature/crashes/src/main/res/layout/item_sort.xml diff --git a/feature/feature-crashes/src/main/res/layout/placeholder_crashes.xml b/feature/crashes/src/main/res/layout/placeholder_crashes.xml similarity index 100% rename from feature/feature-crashes/src/main/res/layout/placeholder_crashes.xml rename to feature/crashes/src/main/res/layout/placeholder_crashes.xml diff --git a/feature/feature-crashes/src/main/res/menu/crash_details_menu.xml b/feature/crashes/src/main/res/menu/crash_details_menu.xml similarity index 100% rename from feature/feature-crashes/src/main/res/menu/crash_details_menu.xml rename to feature/crashes/src/main/res/menu/crash_details_menu.xml diff --git a/feature/feature-crashes/src/main/res/menu/crashes_menu.xml b/feature/crashes/src/main/res/menu/crashes_menu.xml similarity index 100% rename from feature/feature-crashes/src/main/res/menu/crashes_menu.xml rename to feature/crashes/src/main/res/menu/crashes_menu.xml diff --git a/feature/feature-logging/build.gradle.kts b/feature/feature-logging/build.gradle.kts deleted file mode 100644 index 42350932..00000000 --- a/feature/feature-logging/build.gradle.kts +++ /dev/null @@ -1,12 +0,0 @@ -plugins { - id("logfox.android.feature") -} - -android.namespace = "com.f0x1d.logfox.feature.logging" - -dependencies { - implementation(projects.feature.featureCrashesCore) - implementation(projects.feature.featureFiltersCore) - implementation(projects.feature.featureLoggingCore) - implementation(projects.feature.featureRecordingsCore) -} diff --git a/feature/feature-filters-core/.gitignore b/feature/filters-core/.gitignore similarity index 100% rename from feature/feature-filters-core/.gitignore rename to feature/filters-core/.gitignore diff --git a/feature/feature-filters-core/build.gradle.kts b/feature/filters-core/build.gradle.kts similarity index 100% rename from feature/feature-filters-core/build.gradle.kts rename to feature/filters-core/build.gradle.kts diff --git a/feature/feature-filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/di/RepositoriesModule.kt b/feature/filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/di/RepositoriesModule.kt similarity index 100% rename from feature/feature-filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/di/RepositoriesModule.kt rename to feature/filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/di/RepositoriesModule.kt diff --git a/feature/feature-filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/repository/FiltersRepository.kt b/feature/filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/repository/FiltersRepository.kt similarity index 100% rename from feature/feature-filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/repository/FiltersRepository.kt rename to feature/filters-core/src/main/kotlin/com/f0x1d/logfox/feature/filters/core/repository/FiltersRepository.kt diff --git a/feature/feature-filters/.gitignore b/feature/filters/.gitignore similarity index 100% rename from feature/feature-filters/.gitignore rename to feature/filters/.gitignore diff --git a/feature/feature-filters/build.gradle.kts b/feature/filters/build.gradle.kts similarity index 57% rename from feature/feature-filters/build.gradle.kts rename to feature/filters/build.gradle.kts index e00c6fad..045b15ad 100644 --- a/feature/feature-filters/build.gradle.kts +++ b/feature/filters/build.gradle.kts @@ -5,8 +5,8 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.filters" dependencies { - implementation(projects.feature.featureAppsPicker) - implementation(projects.feature.featureFiltersCore) + implementation(projects.feature.appsPicker) + implementation(projects.feature.filtersCore) implementation(libs.gson) } diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/FiltersAdapter.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/FiltersAdapter.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/FiltersAdapter.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/adapter/FiltersAdapter.kt diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/di/EditFilterViewModelModule.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/di/EditFilterViewModelModule.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/di/EditFilterViewModelModule.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/di/EditFilterViewModelModule.kt diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/EditFilterFragment.kt diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/FiltersFragment.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/FiltersFragment.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/FiltersFragment.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/fragment/FiltersFragment.kt diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/viewholder/FilterViewHolder.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/viewholder/FilterViewHolder.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/viewholder/FilterViewHolder.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/ui/viewholder/FilterViewHolder.kt diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/EditFilterViewModel.kt diff --git a/feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/FiltersViewModel.kt b/feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/FiltersViewModel.kt similarity index 100% rename from feature/feature-filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/FiltersViewModel.kt rename to feature/filters/src/main/kotlin/com/f0x1d/logfox/feature/filters/viewmodel/FiltersViewModel.kt diff --git a/feature/feature-filters/src/main/res/layout/fragment_edit_filter.xml b/feature/filters/src/main/res/layout/fragment_edit_filter.xml similarity index 100% rename from feature/feature-filters/src/main/res/layout/fragment_edit_filter.xml rename to feature/filters/src/main/res/layout/fragment_edit_filter.xml diff --git a/feature/feature-filters/src/main/res/layout/fragment_filters.xml b/feature/filters/src/main/res/layout/fragment_filters.xml similarity index 100% rename from feature/feature-filters/src/main/res/layout/fragment_filters.xml rename to feature/filters/src/main/res/layout/fragment_filters.xml diff --git a/feature/feature-filters/src/main/res/layout/item_filter.xml b/feature/filters/src/main/res/layout/item_filter.xml similarity index 100% rename from feature/feature-filters/src/main/res/layout/item_filter.xml rename to feature/filters/src/main/res/layout/item_filter.xml diff --git a/feature/feature-filters/src/main/res/layout/placeholder_filters.xml b/feature/filters/src/main/res/layout/placeholder_filters.xml similarity index 100% rename from feature/feature-filters/src/main/res/layout/placeholder_filters.xml rename to feature/filters/src/main/res/layout/placeholder_filters.xml diff --git a/feature/feature-filters/src/main/res/menu/edit_filter_menu.xml b/feature/filters/src/main/res/menu/edit_filter_menu.xml similarity index 100% rename from feature/feature-filters/src/main/res/menu/edit_filter_menu.xml rename to feature/filters/src/main/res/menu/edit_filter_menu.xml diff --git a/feature/feature-filters/src/main/res/menu/filters_menu.xml b/feature/filters/src/main/res/menu/filters_menu.xml similarity index 100% rename from feature/feature-filters/src/main/res/menu/filters_menu.xml rename to feature/filters/src/main/res/menu/filters_menu.xml diff --git a/feature/feature-logging-core/.gitignore b/feature/logging-core/.gitignore similarity index 100% rename from feature/feature-logging-core/.gitignore rename to feature/logging-core/.gitignore diff --git a/feature/feature-logging-core/build.gradle.kts b/feature/logging-core/build.gradle.kts similarity index 100% rename from feature/feature-logging-core/build.gradle.kts rename to feature/logging-core/build.gradle.kts diff --git a/feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/RepositoriesModule.kt b/feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/RepositoriesModule.kt similarity index 100% rename from feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/RepositoriesModule.kt rename to feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/RepositoriesModule.kt diff --git a/feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/StoresModule.kt b/feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/StoresModule.kt similarity index 100% rename from feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/StoresModule.kt rename to feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/di/StoresModule.kt diff --git a/feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/model/LogLinesExt.kt b/feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/model/LogLinesExt.kt similarity index 100% rename from feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/model/LogLinesExt.kt rename to feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/model/LogLinesExt.kt diff --git a/feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/repository/LoggingRepository.kt b/feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/repository/LoggingRepository.kt similarity index 100% rename from feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/repository/LoggingRepository.kt rename to feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/repository/LoggingRepository.kt diff --git a/feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/store/LoggingStore.kt b/feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/store/LoggingStore.kt similarity index 100% rename from feature/feature-logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/store/LoggingStore.kt rename to feature/logging-core/src/main/kotlin/com/f0x1d/logfox/feature/logging/core/store/LoggingStore.kt diff --git a/feature/feature-logging/.gitignore b/feature/logging/.gitignore similarity index 100% rename from feature/feature-logging/.gitignore rename to feature/logging/.gitignore diff --git a/feature/logging/build.gradle.kts b/feature/logging/build.gradle.kts new file mode 100644 index 00000000..26490df9 --- /dev/null +++ b/feature/logging/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("logfox.android.feature") +} + +android.namespace = "com.f0x1d.logfox.feature.logging" + +dependencies { + implementation(projects.feature.crashesCore) + implementation(projects.feature.filtersCore) + implementation(projects.feature.loggingCore) + implementation(projects.feature.recordingsCore) +} diff --git a/feature/feature-logging/src/main/AndroidManifest.xml b/feature/logging/src/main/AndroidManifest.xml similarity index 100% rename from feature/feature-logging/src/main/AndroidManifest.xml rename to feature/logging/src/main/AndroidManifest.xml diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/adapter/LogsAdapter.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/di/LogsViewModelModule.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/di/LogsViewModelModule.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/di/LogsViewModelModule.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/di/LogsViewModelModule.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/service/LoggingService.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/MainActivityPendingIntentProvider.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/service/MainActivityPendingIntentProvider.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/service/MainActivityPendingIntentProvider.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/service/MainActivityPendingIntentProvider.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/dialog/SearchBottomSheet.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/dialog/SearchBottomSheet.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/dialog/SearchBottomSheet.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/dialog/SearchBottomSheet.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsExtendedCopyFragment.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsExtendedCopyFragment.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsExtendedCopyFragment.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsExtendedCopyFragment.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/fragment/LogsFragment.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/viewholder/LogViewHolder.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/viewholder/LogViewHolder.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/ui/viewholder/LogViewHolder.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/ui/viewholder/LogViewHolder.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/LogsViewModel.kt diff --git a/feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/UriExt.kt b/feature/logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/UriExt.kt similarity index 100% rename from feature/feature-logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/UriExt.kt rename to feature/logging/src/main/kotlin/com/f0x1d/feature/logging/viewmodel/UriExt.kt diff --git a/feature/feature-logging/src/main/res/layout/fragment_logs.xml b/feature/logging/src/main/res/layout/fragment_logs.xml similarity index 100% rename from feature/feature-logging/src/main/res/layout/fragment_logs.xml rename to feature/logging/src/main/res/layout/fragment_logs.xml diff --git a/feature/feature-logging/src/main/res/layout/fragment_logs_extended_copy.xml b/feature/logging/src/main/res/layout/fragment_logs_extended_copy.xml similarity index 100% rename from feature/feature-logging/src/main/res/layout/fragment_logs_extended_copy.xml rename to feature/logging/src/main/res/layout/fragment_logs_extended_copy.xml diff --git a/feature/feature-logging/src/main/res/layout/item_log.xml b/feature/logging/src/main/res/layout/item_log.xml similarity index 100% rename from feature/feature-logging/src/main/res/layout/item_log.xml rename to feature/logging/src/main/res/layout/item_log.xml diff --git a/feature/feature-logging/src/main/res/layout/placeholder_logs.xml b/feature/logging/src/main/res/layout/placeholder_logs.xml similarity index 100% rename from feature/feature-logging/src/main/res/layout/placeholder_logs.xml rename to feature/logging/src/main/res/layout/placeholder_logs.xml diff --git a/feature/feature-logging/src/main/res/layout/sheet_search.xml b/feature/logging/src/main/res/layout/sheet_search.xml similarity index 100% rename from feature/feature-logging/src/main/res/layout/sheet_search.xml rename to feature/logging/src/main/res/layout/sheet_search.xml diff --git a/feature/feature-logging/src/main/res/menu/log_menu.xml b/feature/logging/src/main/res/menu/log_menu.xml similarity index 100% rename from feature/feature-logging/src/main/res/menu/log_menu.xml rename to feature/logging/src/main/res/menu/log_menu.xml diff --git a/feature/feature-logging/src/main/res/menu/logs_menu.xml b/feature/logging/src/main/res/menu/logs_menu.xml similarity index 100% rename from feature/feature-logging/src/main/res/menu/logs_menu.xml rename to feature/logging/src/main/res/menu/logs_menu.xml diff --git a/feature/feature-recordings-core/.gitignore b/feature/recordings-core/.gitignore similarity index 100% rename from feature/feature-recordings-core/.gitignore rename to feature/recordings-core/.gitignore diff --git a/feature/feature-recordings-core/build.gradle.kts b/feature/recordings-core/build.gradle.kts similarity index 69% rename from feature/feature-recordings-core/build.gradle.kts rename to feature/recordings-core/build.gradle.kts index be5c1e3f..3812f347 100644 --- a/feature/feature-recordings-core/build.gradle.kts +++ b/feature/recordings-core/build.gradle.kts @@ -5,5 +5,5 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.recordings.core" dependencies { - implementation(projects.feature.featureLoggingCore) + implementation(projects.feature.loggingCore) } diff --git a/feature/feature-recordings-core/src/main/AndroidManifest.xml b/feature/recordings-core/src/main/AndroidManifest.xml similarity index 100% rename from feature/feature-recordings-core/src/main/AndroidManifest.xml rename to feature/recordings-core/src/main/AndroidManifest.xml diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingController.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingController.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingController.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingController.kt diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/RecordingNotificationController.kt diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/reader/RecordingReader.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/reader/RecordingReader.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/reader/RecordingReader.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/controller/reader/RecordingReader.kt diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/ControllersModule.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/ControllersModule.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/ControllersModule.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/ControllersModule.kt diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/RepositoriesModule.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/RepositoriesModule.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/RepositoriesModule.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/di/RepositoriesModule.kt diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/receiver/RecordingReceiver.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/receiver/RecordingReceiver.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/receiver/RecordingReceiver.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/receiver/RecordingReceiver.kt diff --git a/feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt b/feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt similarity index 100% rename from feature/feature-recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt rename to feature/recordings-core/src/main/kotlin/com/f0x1d/logfox/feature/recordings/core/repository/RecordingsRepository.kt diff --git a/feature/feature-recordings/.gitignore b/feature/recordings/.gitignore similarity index 100% rename from feature/feature-recordings/.gitignore rename to feature/recordings/.gitignore diff --git a/feature/feature-recordings/build.gradle.kts b/feature/recordings/build.gradle.kts similarity index 67% rename from feature/feature-recordings/build.gradle.kts rename to feature/recordings/build.gradle.kts index 210a6780..307d674f 100644 --- a/feature/feature-recordings/build.gradle.kts +++ b/feature/recordings/build.gradle.kts @@ -5,5 +5,5 @@ plugins { android.namespace = "com.f0x1d.logfox.feature.recordings" dependencies { - implementation(projects.feature.featureRecordingsCore) + implementation(projects.feature.recordingsCore) } diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/adapter/RecordingsAdapter.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/adapter/RecordingsAdapter.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/adapter/RecordingsAdapter.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/adapter/RecordingsAdapter.kt diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/di/RecordingViewModelModule.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/di/RecordingViewModelModule.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/di/RecordingViewModelModule.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/di/RecordingViewModelModule.kt diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/dialog/RecordingBottomSheet.kt diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/fragment/RecordingsFragment.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/fragment/RecordingsFragment.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/fragment/RecordingsFragment.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/fragment/RecordingsFragment.kt diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/viewholder/RecordingViewHolder.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/viewholder/RecordingViewHolder.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/viewholder/RecordingViewHolder.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/ui/viewholder/RecordingViewHolder.kt diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingViewModel.kt diff --git a/feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt b/feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt similarity index 100% rename from feature/feature-recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt rename to feature/recordings/src/main/kotlin/com/f0x1d/logfox/feature/recordings/viewmodel/RecordingsViewModel.kt diff --git a/feature/feature-recordings/src/main/res/layout/fragment_recordings.xml b/feature/recordings/src/main/res/layout/fragment_recordings.xml similarity index 100% rename from feature/feature-recordings/src/main/res/layout/fragment_recordings.xml rename to feature/recordings/src/main/res/layout/fragment_recordings.xml diff --git a/feature/feature-recordings/src/main/res/layout/item_recording.xml b/feature/recordings/src/main/res/layout/item_recording.xml similarity index 100% rename from feature/feature-recordings/src/main/res/layout/item_recording.xml rename to feature/recordings/src/main/res/layout/item_recording.xml diff --git a/feature/feature-recordings/src/main/res/layout/placeholder_recordings.xml b/feature/recordings/src/main/res/layout/placeholder_recordings.xml similarity index 100% rename from feature/feature-recordings/src/main/res/layout/placeholder_recordings.xml rename to feature/recordings/src/main/res/layout/placeholder_recordings.xml diff --git a/feature/feature-recordings/src/main/res/layout/sheet_recording.xml b/feature/recordings/src/main/res/layout/sheet_recording.xml similarity index 100% rename from feature/feature-recordings/src/main/res/layout/sheet_recording.xml rename to feature/recordings/src/main/res/layout/sheet_recording.xml diff --git a/feature/feature-recordings/src/main/res/menu/recordings_menu.xml b/feature/recordings/src/main/res/menu/recordings_menu.xml similarity index 100% rename from feature/feature-recordings/src/main/res/menu/recordings_menu.xml rename to feature/recordings/src/main/res/menu/recordings_menu.xml diff --git a/feature/feature-settings/.gitignore b/feature/settings/.gitignore similarity index 100% rename from feature/feature-settings/.gitignore rename to feature/settings/.gitignore diff --git a/feature/feature-settings/build.gradle.kts b/feature/settings/build.gradle.kts similarity index 100% rename from feature/feature-settings/build.gradle.kts rename to feature/settings/build.gradle.kts diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/IntArrayExt.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/IntArrayExt.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/IntArrayExt.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/IntArrayExt.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/LoggingServiceDelegate.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/LoggingServiceDelegate.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/LoggingServiceDelegate.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/LoggingServiceDelegate.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsCrashesFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsCrashesFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsCrashesFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsCrashesFragment.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsLinksFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsLinksFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsLinksFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsLinksFragment.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsMenuFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsMenuFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsMenuFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsMenuFragment.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsNotificationsFragment.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsServiceFragment.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt diff --git a/feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt similarity index 100% rename from feature/feature-settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt rename to feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/base/BasePreferenceFragment.kt diff --git a/feature/feature-settings/src/main/res/layout/preference_material_switch.xml b/feature/settings/src/main/res/layout/preference_material_switch.xml similarity index 100% rename from feature/feature-settings/src/main/res/layout/preference_material_switch.xml rename to feature/settings/src/main/res/layout/preference_material_switch.xml diff --git a/feature/feature-settings/src/main/res/layout/preference_warning.xml b/feature/settings/src/main/res/layout/preference_warning.xml similarity index 100% rename from feature/feature-settings/src/main/res/layout/preference_warning.xml rename to feature/settings/src/main/res/layout/preference_warning.xml diff --git a/feature/feature-settings/src/main/res/values/ids.xml b/feature/settings/src/main/res/values/ids.xml similarity index 100% rename from feature/feature-settings/src/main/res/values/ids.xml rename to feature/settings/src/main/res/values/ids.xml diff --git a/feature/feature-settings/src/main/res/xml/settings_crashes.xml b/feature/settings/src/main/res/xml/settings_crashes.xml similarity index 100% rename from feature/feature-settings/src/main/res/xml/settings_crashes.xml rename to feature/settings/src/main/res/xml/settings_crashes.xml diff --git a/feature/feature-settings/src/main/res/xml/settings_links.xml b/feature/settings/src/main/res/xml/settings_links.xml similarity index 100% rename from feature/feature-settings/src/main/res/xml/settings_links.xml rename to feature/settings/src/main/res/xml/settings_links.xml diff --git a/feature/feature-settings/src/main/res/xml/settings_menu.xml b/feature/settings/src/main/res/xml/settings_menu.xml similarity index 100% rename from feature/feature-settings/src/main/res/xml/settings_menu.xml rename to feature/settings/src/main/res/xml/settings_menu.xml diff --git a/feature/feature-settings/src/main/res/xml/settings_notifications.xml b/feature/settings/src/main/res/xml/settings_notifications.xml similarity index 100% rename from feature/feature-settings/src/main/res/xml/settings_notifications.xml rename to feature/settings/src/main/res/xml/settings_notifications.xml diff --git a/feature/feature-settings/src/main/res/xml/settings_service.xml b/feature/settings/src/main/res/xml/settings_service.xml similarity index 100% rename from feature/feature-settings/src/main/res/xml/settings_service.xml rename to feature/settings/src/main/res/xml/settings_service.xml diff --git a/feature/feature-settings/src/main/res/xml/settings_ui.xml b/feature/settings/src/main/res/xml/settings_ui.xml similarity index 100% rename from feature/feature-settings/src/main/res/xml/settings_ui.xml rename to feature/settings/src/main/res/xml/settings_ui.xml diff --git a/feature/feature-setup/.gitignore b/feature/setup/.gitignore similarity index 100% rename from feature/feature-setup/.gitignore rename to feature/setup/.gitignore diff --git a/feature/feature-setup/build.gradle.kts b/feature/setup/build.gradle.kts similarity index 100% rename from feature/feature-setup/build.gradle.kts rename to feature/setup/build.gradle.kts diff --git a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/SetupFragment.kt b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/SetupFragment.kt similarity index 100% rename from feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/SetupFragment.kt rename to feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/SetupFragment.kt diff --git a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt similarity index 100% rename from feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt rename to feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenContent.kt diff --git a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenState.kt b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenState.kt similarity index 100% rename from feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenState.kt rename to feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/ui/fragment/setup/compose/SetupScreenState.kt diff --git a/feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt similarity index 100% rename from feature/feature-setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt rename to feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/viewmodel/SetupViewModel.kt diff --git a/feature/feature-setup/src/test/kotlin/com/f0x1d/logfox/setup/compose/SetupScreenContentTest.kt b/feature/setup/src/test/kotlin/com/f0x1d/logfox/setup/compose/SetupScreenContentTest.kt similarity index 100% rename from feature/feature-setup/src/test/kotlin/com/f0x1d/logfox/setup/compose/SetupScreenContentTest.kt rename to feature/setup/src/test/kotlin/com/f0x1d/logfox/setup/compose/SetupScreenContentTest.kt diff --git a/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldOpenAdbDialogOnSetupScreenContent.png b/feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldOpenAdbDialogOnSetupScreenContent.png similarity index 100% rename from feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldOpenAdbDialogOnSetupScreenContent.png rename to feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldOpenAdbDialogOnSetupScreenContent.png diff --git a/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowAdbDialogOnSetupScreenContent.png b/feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowAdbDialogOnSetupScreenContent.png similarity index 100% rename from feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowAdbDialogOnSetupScreenContent.png rename to feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowAdbDialogOnSetupScreenContent.png diff --git a/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png b/feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png similarity index 100% rename from feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png rename to feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowDarkSetupScreenContent.png diff --git a/feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png b/feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png similarity index 100% rename from feature/feature-setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png rename to feature/setup/src/test/screenshots/com.f0x1d.logfox.setup.compose.SetupScreenContentTest.shouldShowSetupScreenContent.png From 3d35e396371d1d52efb5b8c41386c5bf3d47c16c Mon Sep 17 00:00:00 2001 From: F0x1d Date: Thu, 15 Aug 2024 02:44:35 +0300 Subject: [PATCH 6/9] [fix]: opening crashes by default --- .../f0x1d/logfox/ui/activity/MainActivity.kt | 34 +++++++++++++------ .../main/res/layout-land/activity_main.xml | 1 - .../res/layout-land/activity_main_no_bar.xml | 1 - app/src/main/res/layout/activity_main.xml | 1 - .../main/res/layout/activity_main_no_bar.xml | 1 - .../ui/fragment/picker/AppsPickerFragment.kt | 1 + .../picker/compose/AppsPickerScreenContent.kt | 10 +++++- .../picker/compose/AppsPickerScreenState.kt | 1 + .../viewmodel/AppsPickerResultHandler.kt | 4 +++ .../viewmodel/list/CrashesViewModel.kt | 5 +++ gradle/libs.versions.toml | 12 +++---- 11 files changed, 50 insertions(+), 21 deletions(-) diff --git a/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt b/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt index dd5b068c..95ee0055 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/ui/activity/MainActivity.kt @@ -27,6 +27,7 @@ import com.f0x1d.logfox.arch.ui.activity.BaseViewModelActivity import com.f0x1d.logfox.arch.viewmodel.Event import com.f0x1d.logfox.databinding.ActivityMainBinding import com.f0x1d.logfox.navigation.Directions +import com.f0x1d.logfox.navigation.NavGraphs import com.f0x1d.logfox.strings.Strings import com.f0x1d.logfox.ui.Icons import com.f0x1d.logfox.viewmodel.MainViewModel @@ -38,7 +39,14 @@ import dagger.hilt.android.AndroidEntryPoint class MainActivity: BaseViewModelActivity(), NavController.OnDestinationChangedListener { override val viewModel by viewModels() - private lateinit var navController: NavController + + private val navController by lazy { + val navHostFragment = supportFragmentManager.findFragmentById( + R.id.nav_host_fragment_content_main, + ) as NavHostFragment + + navHostFragment.navController + } private val requestNotificationPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission(), @@ -65,19 +73,13 @@ class MainActivity: BaseViewModelActivity(), @SuppressLint("InlinedApi") override fun ActivityMainBinding.onCreate(savedInstanceState: Bundle?) { - val navHostFragment = supportFragmentManager.findFragmentById( - R.id.nav_host_fragment_content_main, - ) as NavHostFragment - navController = navHostFragment.navController + setupNavigation() - barView?.setupWithNavController(navController) barView?.setOnItemReselectedListener { // Just do nothing } setupBarInsets() - navController.addOnDestinationChangedListener(this@MainActivity) - if (!hasNotificationsPermission() && !viewModel.askedNotificationsPermission) { MaterialAlertDialogBuilder(this@MainActivity) .setIcon(Icons.ic_dialog_notification_important) @@ -92,10 +94,22 @@ class MainActivity: BaseViewModelActivity(), viewModel.askedNotificationsPermission = true } + } - if (savedInstanceState == null && viewModel.openCrashesOnStartup) { - navController.navigate(Directions.crashes) + private fun ActivityMainBinding.setupNavigation() { + navController.graph = navController.navInflater.inflate(NavGraphs.nav_graph).apply { + setStartDestination( + startDestId = if (viewModel.openCrashesOnStartup) { + Directions.crashes + } else { + Directions.logs + }, + ) } + + barView?.setupWithNavController(navController) + + navController.addOnDestinationChangedListener(this@MainActivity) } override fun onPostCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml index a1337b65..89e5ad98 100644 --- a/app/src/main/res/layout-land/activity_main.xml +++ b/app/src/main/res/layout-land/activity_main.xml @@ -15,7 +15,6 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/navigation_rail" app:layout_constraintBottom_toBottomOf="parent" - app:navGraph="@navigation/nav_graph" tools:layout="@layout/fragment_logs" /> () { state to checkedApps }.map { (state, checkedAppPackageNames) -> state.copy( + topBarTitle = handler.provideTopAppBarTitle(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 77e1f6d4..be685f33 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 @@ -93,7 +93,15 @@ private fun AppsSearchBar( onSearch = { /* noop */ }, active = state.searchActive, onActiveChange = listener.onSearchActiveChanged, - placeholder = { Text(text = stringResource(id = Strings.apps)) }, + placeholder = { + Text( + text = if (state.searchActive) { + stringResource(id = Strings.apps) + } else { + state.topBarTitle + }, + ) + }, leadingIcon = { NavigationBackButton(onClick = listener.onBackClicked) }, ) { AppsContent( diff --git a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt index bad1efed..71ea5f39 100644 --- a/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt +++ b/feature/apps-picker/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/ui/fragment/picker/compose/AppsPickerScreenState.kt @@ -7,6 +7,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentSetOf data class AppsPickerScreenState( + val topBarTitle: String = "Apps", val apps: ImmutableList = persistentListOf(), val checkedAppPackageNames: ImmutableSet = persistentSetOf(), val searchedApps: ImmutableList = persistentListOf(), 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 4d3e4a3b..74735db7 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 @@ -1,9 +1,11 @@ package com.f0x1d.logfox.feature.apps.picker.viewmodel import android.annotation.SuppressLint +import android.content.Context import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.f0x1d.logfox.model.InstalledApp +import com.f0x1d.logfox.strings.Strings import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -11,6 +13,8 @@ interface AppsPickerResultHandler { val supportsMultiplySelection: Boolean get() = false val checkedAppPackageNames: Flow> get() = flowOf(emptySet()) + fun provideTopAppBarTitle(context: Context) = context.getString(Strings.apps) + fun onAppChecked(app: InstalledApp, checked: Boolean) = Unit // pass true to close fragment 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 6c31e54b..95869d00 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 @@ -1,6 +1,7 @@ package com.f0x1d.logfox.feature.crashes.viewmodel.list import android.app.Application +import android.content.Context import androidx.lifecycle.viewModelScope import com.f0x1d.logfox.arch.di.DefaultDispatcher import com.f0x1d.logfox.arch.di.IODispatcher @@ -14,6 +15,7 @@ import com.f0x1d.logfox.feature.crashes.core.repository.DisabledAppsRepository import com.f0x1d.logfox.model.InstalledApp import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.preferences.shared.crashes.CrashesSort +import com.f0x1d.logfox.strings.Strings import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.delay @@ -141,6 +143,9 @@ class CrashesViewModel @Inject constructor( apps.map(DisabledApp::packageName).toSet() } + override fun provideTopAppBarTitle(context: Context): String = + context.getString(Strings.blacklist) + override fun onAppChecked(app: InstalledApp, checked: Boolean) { viewModelScope.launch { disabledAppsRepository.checkApp(app.packageName, checked) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4dde1c6c..c2519452 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,17 +6,17 @@ targetSdk = "34" kotlin = "2.0.0" kotlinx-immutable-collections = "0.3.7" -androidGradlePlugin = "8.5.0" +androidGradlePlugin = "8.5.2" ksp = "2.0.0-1.0.22" hilt = "2.49" androidx-appcompat = "1.7.0" androidx-constraintlayout = "2.1.4" androidx-core = "1.13.1" -androidx-collection = "1.4.0" -androidx-fragment = "1.8.1" -androidx-activity = "1.9.0" +androidx-collection = "1.4.3" +androidx-fragment = "1.8.2" +androidx-activity = "1.9.1" androidx-hilt-navigation-fragment = "1.2.0" -androidx-lifecycle = "2.8.3" +androidx-lifecycle = "2.8.4" androidx-navigation = "2.7.7" androidx-preference = "1.2.1" androidx-recyclerview = "1.3.2" @@ -34,7 +34,7 @@ flow-preferences = "1.9.1" timber = "5.0.1" libsu = "6.0.0" junit = "4.13.2" -robolectric = "4.12.2" +robolectric = "4.13" roborazzi = "1.21.0" androidx-test-core = "1.6.1" androidx-test-ext-junit = "1.2.1" From 29682928e03790e73edc17470ff124582d2787bc Mon Sep 17 00:00:00 2001 From: F0x1d Date: Sat, 17 Aug 2024 16:16:55 +0300 Subject: [PATCH 7/9] [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 From 47655c3a1bff1a90942b2cfa1e20017ec5fa4bbf Mon Sep 17 00:00:00 2001 From: F0x1d Date: Sun, 18 Aug 2024 14:43:20 +0300 Subject: [PATCH 8/9] [feat]: search text in crash log --- .../main/kotlin/com/f0x1d/logfox/ui/Colors.kt | 3 + core/ui/src/main/res/drawable/ic_search.xml | 3 +- .../ui/fragment/CrashDetailsFragment.kt | 71 +++++++++++++++++++ .../viewmodel/list/CrashesViewModel.kt | 53 +++++--------- .../src/main/res/menu/crash_details_menu.xml | 7 ++ 5 files changed, 99 insertions(+), 38 deletions(-) create mode 100644 core/ui/src/main/kotlin/com/f0x1d/logfox/ui/Colors.kt diff --git a/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/Colors.kt b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/Colors.kt new file mode 100644 index 00000000..17b78dc7 --- /dev/null +++ b/core/ui/src/main/kotlin/com/f0x1d/logfox/ui/Colors.kt @@ -0,0 +1,3 @@ +package com.f0x1d.logfox.ui + +typealias Colors = R.color diff --git a/core/ui/src/main/res/drawable/ic_search.xml b/core/ui/src/main/res/drawable/ic_search.xml index f9e527d9..ac752f9b 100644 --- a/core/ui/src/main/res/drawable/ic_search.xml +++ b/core/ui/src/main/res/drawable/ic_search.xml @@ -1,9 +1,10 @@ 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 a32dab13..a11af621 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 @@ -5,10 +5,17 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.provider.Settings +import android.text.Spannable +import android.text.style.BackgroundColorSpan import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import android.widget.TextView +import androidx.activity.OnBackPressedCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.widget.SearchView +import androidx.core.text.toSpannable import androidx.core.view.isVisible import androidx.fragment.app.viewModels import androidx.navigation.fragment.findNavController @@ -22,6 +29,7 @@ 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.Colors import com.f0x1d.logfox.ui.Icons import com.f0x1d.logfox.ui.dialog.showAreYouSureDeleteDialog import com.f0x1d.logfox.ui.dialog.showAreYouSureDialog @@ -30,6 +38,7 @@ import com.f0x1d.logfox.ui.view.setClickListenerOn import com.f0x1d.logfox.ui.view.setupBackButtonForNavController import dagger.hilt.android.AndroidEntryPoint import dev.chrisbanes.insetter.applyInsetter +import java.util.Locale @AndroidEntryPoint class CrashDetailsFragment: BaseViewModelFragment() { @@ -42,6 +51,12 @@ class CrashDetailsFragment: BaseViewModelFragment - crashes to query - }.collectLatest { (crashes, query) -> - - fun AppCrash.suits(query: String): Boolean = - packageName.contains(query, ignoreCase = true) - || appName?.contains(query, ignoreCase = true) == true - - val filteredCrashes = withContext(defaultDispatcher) { - crashes.filter { it.suits(query) }.map { AppCrashesCount(it) } - } - - send(filteredCrashes) - delay(SEARCH_DEBOUNCE_MILLIS) // Maybe no need to search content for now - - val deeplyFilteredCrashes = withContext(defaultDispatcher) { - crashes.filter { crash -> - val fileContentSettles = withContext(ioDispatcher) { - crash.logFile?.readText()?.contains(query, ignoreCase = true) == true - } - - crash.suits(query) || fileContentSettles - }.map { AppCrashesCount(it) } - } - send(deeplyFilteredCrashes) + val searchedCrashes = combine( + crashesRepository.getAllAsFlow(), + query, + ) { crashes, query -> crashes to query } + .map { (crashes, query) -> + crashes.filter { crash -> + crash.packageName.contains(query, ignoreCase = true) + || crash.appName?.contains(query, ignoreCase = true) == true + }.map { AppCrashesCount(it) } } - }.stateIn( - scope = viewModelScope, - started = SharingStarted.Eagerly, - initialValue = emptyList(), - ) + .distinctUntilChanged() + .flowOn(defaultDispatcher) + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = emptyList(), + ) fun updateQuery(query: String) = this.query.update { query } 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 7f49c646..39819cdd 100644 --- a/feature/crashes/src/main/res/menu/crash_details_menu.xml +++ b/feature/crashes/src/main/res/menu/crash_details_menu.xml @@ -2,6 +2,13 @@ + + Date: Sun, 18 Aug 2024 21:51:08 +0300 Subject: [PATCH 9/9] [feat]: disabling monet --- app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt | 8 +++++++- core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt | 1 + .../f0x1d/logfox/preferences/shared/AppPreferences.kt | 4 ++++ .../feature/settings/ui/fragment/SettingsUIFragment.kt | 9 +++++++++ feature/settings/src/main/res/xml/settings_ui.xml | 8 ++++++++ strings/src/main/res/values/strings.xml | 1 + 6 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt b/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt index 2a2b0767..23d545b7 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/LogFoxApp.kt @@ -12,6 +12,7 @@ import com.f0x1d.logfox.arch.notificationManagerCompat import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.strings.Strings import com.google.android.material.color.DynamicColors +import com.google.android.material.color.DynamicColorsOptions import dagger.hilt.android.HiltAndroidApp import javax.inject.Inject @@ -27,7 +28,12 @@ class LogFoxApp: Application(), ImageLoaderFactory { override fun onCreate() { super.onCreate() AppCompatDelegate.setDefaultNightMode(appPreferences.nightTheme) - DynamicColors.applyToActivitiesIfAvailable(this) + DynamicColors.applyToActivitiesIfAvailable( + this, + DynamicColorsOptions.Builder() + .setPrecondition { _, _ -> appPreferences.monetEnabled } + .build() + ) notificationManagerCompat.apply { val loggingStatusChannel = NotificationChannelCompat.Builder( diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt index 0f55769c..c7f192e0 100644 --- a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt +++ b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/API.kt @@ -20,3 +20,4 @@ import androidx.annotation.ChecksSdkIntAtLeast @get:ChecksSdkIntAtLeast(api = R) val canPickJSON = SDK_INT >= R @get:ChecksSdkIntAtLeast(api = S) val mutablePendingIntentAvailable = SDK_INT >= S +@get:ChecksSdkIntAtLeast(api = S) val monetAvailable = mutablePendingIntentAvailable diff --git a/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt b/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt index fcb7206c..b0ffe54c 100644 --- a/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt +++ b/core/preferences/src/main/kotlin/com/f0x1d/logfox/preferences/shared/AppPreferences.kt @@ -41,6 +41,10 @@ class AppPreferences @Inject constructor( defaultValue = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, ).asFlow() + var monetEnabled + get() = get("pref_monet_enabled", true) + set(value) { put("pref_monet_enabled", value) } + var dateFormat get() = getNullable("pref_date_format", DATE_FORMAT_DEFAULT) set(value) { put("pref_date_format", value) } diff --git a/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt index 3fce5e54..045ec88a 100644 --- a/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt +++ b/feature/settings/src/main/kotlin/com/f0x1d/logfox/feature/settings/ui/fragment/SettingsUIFragment.kt @@ -5,6 +5,7 @@ import android.text.InputType import androidx.appcompat.app.AppCompatDelegate import androidx.preference.Preference import com.f0x1d.logfox.arch.catchingNotNumber +import com.f0x1d.logfox.arch.monetAvailable import com.f0x1d.logfox.feature.settings.R import com.f0x1d.logfox.feature.settings.fillWithStrings import com.f0x1d.logfox.feature.settings.ui.fragment.base.BasePreferenceFragment @@ -56,6 +57,14 @@ class SettingsUIFragment: BasePreferenceFragment() { } } + findPreference("pref_monet_enabled")?.apply { + isVisible = monetAvailable + setOnPreferenceChangeListener { _, _ -> + requireActivity().recreate() + return@setOnPreferenceChangeListener true + } + } + findPreference("pref_date_format")?.apply { setupAsEditTextPreference( setupViews = { it.textLayout.setHint(Strings.date_format) }, diff --git a/feature/settings/src/main/res/xml/settings_ui.xml b/feature/settings/src/main/res/xml/settings_ui.xml index 81f1a8dd..da43f599 100644 --- a/feature/settings/src/main/res/xml/settings_ui.xml +++ b/feature/settings/src/main/res/xml/settings_ui.xml @@ -7,6 +7,14 @@ android:title="@string/night_theme" android:key="pref_night_theme" app:iconSpaceReserved="false" /> + + Add to blacklist Remove from blacklist Are you sure want to add this app to blacklist? LogFox does not observe crashes for blacklisted apps + Monet