From b20b0730f8d76dd62591445cd60e9cb51d221cc4 Mon Sep 17 00:00:00 2001 From: Maksim Zoteev <39910552+F0x1d@users.noreply.github.com> Date: Sat, 16 Nov 2024 01:50:36 +0300 Subject: [PATCH] [feat]: update v2.0.5 * [fix]: not working exit button if logging is stuck * [fix]: filters loglevel crash * [fix]: monet setting not being applied to compose screens --- app/build.gradle.kts | 1 + .../kotlin/com/f0x1d/logfox}/di/GsonModule.kt | 7 +- .../com/f0x1d/logfox/receiver/BootReceiver.kt | 4 +- core/arch/build.gradle.kts | 5 +- .../f0x1d/logfox/arch/di/DispatchersModule.kt | 2 +- .../DynamicColorAvailabilityProviderModule.kt | 22 ++++++ .../com/f0x1d/logfox/arch/di/UtilsModule.kt | 2 +- .../presentation/ui/activity/BaseActivity.kt | 9 +-- .../fragment/compose/BaseComposeFragment.kt | 25 +++++- .../DynamicColorAvailabilityProvider.kt | 5 ++ core/database/build.gradle.kts | 2 - .../logfox/database}/annotations/GsonSkip.kt | 2 +- .../logfox/database/entity/UserFilter.kt | 2 +- .../com/f0x1d/logfox/datetime/ContextExt.kt | 9 +-- .../logfox/preferences/shared/ContextExt.kt | 9 +-- core/ui/build.gradle.kts | 1 - .../com/f0x1d/logfox/ui/view/PreferenceExt.kt | 4 +- .../presentation/ui/AppsPickerFragment.kt | 13 ++-- .../edit/presentation/EditFilterState.kt | 3 +- .../edit/presentation/EditFilterViewModel.kt | 2 +- .../impl/data/LoggingRepositoryImpl.kt | 76 ++++++++++--------- .../presentation/ui/RecordingsFragment.kt | 15 ++-- .../setup/presentation/ui/SetupFragment.kt | 17 ++--- .../ui/compose/SetupScreenContent.kt | 20 ++--- 24 files changed, 148 insertions(+), 109 deletions(-) rename {core/arch/src/main/kotlin/com/f0x1d/logfox/arch => app/src/main/kotlin/com/f0x1d/logfox}/di/GsonModule.kt (81%) create mode 100644 core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DynamicColorAvailabilityProviderModule.kt create mode 100644 core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/DynamicColorAvailabilityProvider.kt rename core/{arch/src/main/kotlin/com/f0x1d/logfox/arch => database/src/main/kotlin/com/f0x1d/logfox/database}/annotations/GsonSkip.kt (56%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a9ac9957..f0fc0bb3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(projects.feature.setup) implementation(libs.timber) + implementation(libs.gson) implementation(libs.viewpump) implementation(libs.coil) diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt b/app/src/main/kotlin/com/f0x1d/logfox/di/GsonModule.kt similarity index 81% rename from core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt rename to app/src/main/kotlin/com/f0x1d/logfox/di/GsonModule.kt index 3d2711d9..f2db28e6 100644 --- a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/GsonModule.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/di/GsonModule.kt @@ -1,8 +1,9 @@ -package com.f0x1d.logfox.arch.di +package com.f0x1d.logfox.di -import com.f0x1d.logfox.arch.annotations.GsonSkip +import com.f0x1d.logfox.database.annotations.GsonSkip import com.google.gson.ExclusionStrategy import com.google.gson.FieldAttributes +import com.google.gson.Gson import com.google.gson.GsonBuilder import dagger.Module import dagger.Provides @@ -16,7 +17,7 @@ object GsonModule { @Provides @Singleton - fun provideGson() = GsonBuilder() + fun provideGson(): Gson = GsonBuilder() .addSerializationExclusionStrategy( object : ExclusionStrategy { override fun shouldSkipField(f: FieldAttributes) = f.getAnnotation(GsonSkip::class.java) != null 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 d32ce56b..e6ca930a 100644 --- a/app/src/main/kotlin/com/f0x1d/logfox/receiver/BootReceiver.kt +++ b/app/src/main/kotlin/com/f0x1d/logfox/receiver/BootReceiver.kt @@ -14,7 +14,7 @@ import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @AndroidEntryPoint -class BootReceiver: BroadcastReceiver() { +class BootReceiver : BroadcastReceiver() { @Inject lateinit var appPreferences: AppPreferences @@ -26,7 +26,7 @@ class BootReceiver: BroadcastReceiver() { } if (context.hasPermissionToReadLogs) { - Intent(context, com.f0x1d.logfox.feature.logging.service.presentation.LoggingService::class.java).let { + Intent(context, LoggingService::class.java).let { if (startForegroundServiceAvailable) context.startForegroundService(it) else diff --git a/core/arch/build.gradle.kts b/core/arch/build.gradle.kts index f2189c0e..fb194c9f 100644 --- a/core/arch/build.gradle.kts +++ b/core/arch/build.gradle.kts @@ -8,7 +8,10 @@ plugins { android.namespace = "com.f0x1d.logfox.arch" dependencies { + implementation(projects.core.ui) + implementation(projects.core.uiCompose) + implementation(projects.core.preferences) + implementation(libs.insetter) implementation(libs.viewpump) - implementation(libs.gson) } diff --git a/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 index 66f302cd..042c78ae 100644 --- a/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 @@ -10,7 +10,7 @@ import javax.inject.Qualifier @Module @InstallIn(SingletonComponent::class) -object DispatchersModule { +internal object DispatchersModule { @MainDispatcher @Provides diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DynamicColorAvailabilityProviderModule.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DynamicColorAvailabilityProviderModule.kt new file mode 100644 index 00000000..a0c84463 --- /dev/null +++ b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/di/DynamicColorAvailabilityProviderModule.kt @@ -0,0 +1,22 @@ +package com.f0x1d.logfox.arch.di + +import com.f0x1d.logfox.arch.presentation.ui.fragment.compose.DynamicColorAvailabilityProvider +import com.f0x1d.logfox.preferences.shared.AppPreferences +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object DynamicColorAvailabilityProviderModule { + + @Provides + @Singleton + fun provideDynamicColorAvailabilityProvider( + appPreferences: AppPreferences, + ): DynamicColorAvailabilityProvider = object : DynamicColorAvailabilityProvider { + override fun isDynamicColorAvailable(): Boolean = appPreferences.monetEnabled + } +} diff --git a/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 index 5dde0f81..80184c08 100644 --- a/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 @@ -8,7 +8,7 @@ import javax.inject.Qualifier @Module @InstallIn(SingletonComponent::class) -object UtilsModule { +internal object UtilsModule { @NullString @Provides diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/activity/BaseActivity.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/activity/BaseActivity.kt index 5686279c..d69416e1 100644 --- a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/activity/BaseActivity.kt +++ b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/activity/BaseActivity.kt @@ -44,12 +44,9 @@ abstract class BaseActivity: AppCompatActivity(), SimpleLifecyc } override fun attachBaseContext(newBase: Context) { - val entryPoint = EntryPointAccessors.fromApplication( - context = newBase, - entryPoint = ViewPumpEntryPoint::class.java, - ) + val entryPoint = EntryPointAccessors.fromApplication(newBase) - super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase, entryPoint.viewPump())) + super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase, entryPoint.viewPump)) } protected fun snackbar(text: String) = binding.root.snackbar(text).apply { @@ -65,6 +62,6 @@ abstract class BaseActivity: AppCompatActivity(), SimpleLifecyc @EntryPoint @InstallIn(SingletonComponent::class) internal interface ViewPumpEntryPoint { - fun viewPump(): ViewPump + val viewPump: ViewPump } } diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/BaseComposeFragment.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/BaseComposeFragment.kt index 9d803276..ba9f29a4 100644 --- a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/BaseComposeFragment.kt +++ b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/BaseComposeFragment.kt @@ -10,9 +10,20 @@ import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import com.f0x1d.logfox.arch.databinding.FragmentComposeBinding import com.f0x1d.logfox.arch.presentation.ui.fragment.BaseFragment +import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.components.SingletonComponent abstract class BaseComposeFragment : BaseFragment() { + private val dynamicColorAvailabilityProvider: DynamicColorAvailabilityProvider by lazy { + EntryPointAccessors + .fromApplication(requireContext()) + .dynamicColorAvailabilityProvider + } + override fun inflateBinding( inflater: LayoutInflater, container: ViewGroup?, @@ -20,7 +31,13 @@ abstract class BaseComposeFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.composeView.setup { Content() } + binding.composeView.setup { + LogFoxTheme( + dynamicColor = dynamicColorAvailabilityProvider.isDynamicColorAvailable(), + ) { + Content() + } + } } @Composable @@ -32,4 +49,10 @@ abstract class BaseComposeFragment : BaseFragment() { setContent(content) } + + @EntryPoint + @InstallIn(SingletonComponent::class) + internal interface BaseComposeFragmentEntryPoint { + val dynamicColorAvailabilityProvider: DynamicColorAvailabilityProvider + } } diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/DynamicColorAvailabilityProvider.kt b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/DynamicColorAvailabilityProvider.kt new file mode 100644 index 00000000..2c681a64 --- /dev/null +++ b/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/presentation/ui/fragment/compose/DynamicColorAvailabilityProvider.kt @@ -0,0 +1,5 @@ +package com.f0x1d.logfox.arch.presentation.ui.fragment.compose + +interface DynamicColorAvailabilityProvider { + fun isDynamicColorAvailable(): Boolean +} diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts index f93c4570..3a4b06dc 100644 --- a/core/database/build.gradle.kts +++ b/core/database/build.gradle.kts @@ -14,8 +14,6 @@ android { } dependencies { - implementation(projects.core.arch) - compileOnly(libs.androidx.compose.runtime) implementation(libs.androidx.room) diff --git a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt b/core/database/src/main/kotlin/com/f0x1d/logfox/database/annotations/GsonSkip.kt similarity index 56% rename from core/arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt rename to core/database/src/main/kotlin/com/f0x1d/logfox/database/annotations/GsonSkip.kt index 4559ea69..6ca8f9d0 100644 --- a/core/arch/src/main/kotlin/com/f0x1d/logfox/arch/annotations/GsonSkip.kt +++ b/core/database/src/main/kotlin/com/f0x1d/logfox/database/annotations/GsonSkip.kt @@ -1,4 +1,4 @@ -package com.f0x1d.logfox.arch.annotations +package com.f0x1d.logfox.database.annotations @Target(AnnotationTarget.FIELD) annotation class GsonSkip diff --git a/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 index c6cef6b6..840d3170 100644 --- a/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 @@ -10,7 +10,7 @@ import androidx.room.PrimaryKey import androidx.room.Query import androidx.room.TypeConverter import androidx.room.Update -import com.f0x1d.logfox.arch.annotations.GsonSkip +import com.f0x1d.logfox.database.annotations.GsonSkip import com.f0x1d.logfox.model.Identifiable import com.f0x1d.logfox.model.logline.LogLevel import kotlinx.coroutines.flow.Flow diff --git a/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt b/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt index 7e76341f..2ae7d8f6 100644 --- a/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt +++ b/core/datetime/src/main/kotlin/com/f0x1d/logfox/datetime/ContextExt.kt @@ -6,13 +6,12 @@ import dagger.hilt.InstallIn import dagger.hilt.android.EntryPointAccessors import dagger.hilt.components.SingletonComponent -val Context.dateTimeFormatter get() = EntryPointAccessors.fromApplication( - context = this, - entryPoint = DateTimeFormatterEntryPoint::class.java, -).dateTimeFormatter() +val Context.dateTimeFormatter get() = EntryPointAccessors + .fromApplication(this) + .dateTimeFormatter @EntryPoint @InstallIn(SingletonComponent::class) private interface DateTimeFormatterEntryPoint { - fun dateTimeFormatter(): DateTimeFormatter + val dateTimeFormatter: DateTimeFormatter } diff --git a/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 index d874d178..531ac616 100644 --- a/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 @@ -6,13 +6,12 @@ import dagger.hilt.InstallIn import dagger.hilt.android.EntryPointAccessors import dagger.hilt.components.SingletonComponent -val Context.appPreferences get() = EntryPointAccessors.fromApplication( - context = this, - entryPoint = AppPreferencesEntryPoint::class.java, -).appPreferences() +val Context.appPreferences get() = EntryPointAccessors + .fromApplication(this) + .appPreferences @EntryPoint @InstallIn(SingletonComponent::class) private interface AppPreferencesEntryPoint { - fun appPreferences(): AppPreferences + val appPreferences: AppPreferences } diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 8a5682c3..73496054 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -6,7 +6,6 @@ plugins { android.namespace = "com.f0x1d.logfox.ui" dependencies { - implementation(projects.core.arch) implementation(projects.core.preferences) implementation(libs.insetter) diff --git a/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 index f69cea29..2cfd9d3d 100644 --- a/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 @@ -2,8 +2,8 @@ package com.f0x1d.logfox.ui.view import android.view.LayoutInflater import android.view.inputmethod.InputMethodManager +import androidx.core.content.getSystemService import androidx.preference.Preference -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 @@ -35,7 +35,7 @@ fun Preference.setupAsEditTextPreference( setSelection(text?.length ?: 0) postDelayed({ - context.inputMethodManager.showSoftInput( + context.getSystemService()?.showSoftInput( this, InputMethodManager.SHOW_IMPLICIT ) diff --git a/feature/apps-picker/impl/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/presentation/ui/AppsPickerFragment.kt b/feature/apps-picker/impl/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/presentation/ui/AppsPickerFragment.kt index 0498ef13..8a6cee5a 100644 --- a/feature/apps-picker/impl/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/presentation/ui/AppsPickerFragment.kt +++ b/feature/apps-picker/impl/src/main/kotlin/com/f0x1d/logfox/feature/apps/picker/presentation/ui/AppsPickerFragment.kt @@ -12,7 +12,6 @@ import com.f0x1d.logfox.feature.apps.picker.AppsPickerResultHandler import com.f0x1d.logfox.feature.apps.picker.presentation.AppsPickerState import com.f0x1d.logfox.feature.apps.picker.presentation.AppsPickerViewModel import com.f0x1d.logfox.feature.apps.picker.presentation.ui.compose.AppsPickerScreenContent -import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme import dagger.hilt.android.AndroidEntryPoint import kotlinx.collections.immutable.toImmutableSet import kotlinx.coroutines.flow.Flow @@ -57,14 +56,12 @@ class AppsPickerFragment : BaseComposeFragment() { @Composable override fun Content() { - LogFoxTheme { - val state by uiState.collectAsState(initial = viewModel.currentState) + val state by uiState.collectAsState(initial = viewModel.currentState) - AppsPickerScreenContent( - state = state, - listener = listener, - ) - } + AppsPickerScreenContent( + state = state, + listener = listener, + ) } @SuppressLint("RestrictedApi") diff --git a/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterState.kt b/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterState.kt index ed3d3ce5..8b51953e 100644 --- a/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterState.kt +++ b/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterState.kt @@ -1,9 +1,10 @@ package com.f0x1d.logfox.feature.filters.edit.presentation import com.f0x1d.logfox.database.entity.UserFilter +import com.f0x1d.logfox.model.logline.LogLevel data class EditFilterState( val filter: UserFilter? = null, val including: Boolean = true, - val enabledLogLevels: List = emptyList(), + val enabledLogLevels: List = List(LogLevel.entries.size) { false }, ) diff --git a/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterViewModel.kt b/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterViewModel.kt index c1319cfc..25b107b8 100644 --- a/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterViewModel.kt +++ b/feature/filters/edit/src/main/kotlin/com/f0x1d/logfox/feature/filters/edit/presentation/EditFilterViewModel.kt @@ -47,7 +47,7 @@ class EditFilterViewModel @Inject constructor( .collect { filter -> if (filter == null) return@collect - val enabledLogLevels = List(7) { false }.toMutableList() + val enabledLogLevels = List(LogLevel.entries.size) { false }.toMutableList() val allowedLevels = filter.allowedLevels.map { it.ordinal } for (i in 0 until enabledLogLevels.size) { enabledLogLevels[i] = allowedLevels.contains(i) diff --git a/feature/logging/impl/src/main/kotlin/com/f0x1d/logfox/feature/logging/impl/data/LoggingRepositoryImpl.kt b/feature/logging/impl/src/main/kotlin/com/f0x1d/logfox/feature/logging/impl/data/LoggingRepositoryImpl.kt index 650a538c..bf43ba11 100644 --- a/feature/logging/impl/src/main/kotlin/com/f0x1d/logfox/feature/logging/impl/data/LoggingRepositoryImpl.kt +++ b/feature/logging/impl/src/main/kotlin/com/f0x1d/logfox/feature/logging/impl/data/LoggingRepositoryImpl.kt @@ -9,16 +9,15 @@ import com.f0x1d.logfox.preferences.shared.AppPreferences import com.f0x1d.logfox.terminals.base.Terminal import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import kotlinx.coroutines.withTimeout +import kotlinx.coroutines.yield import timber.log.Timber +import java.io.BufferedReader import javax.inject.Inject import kotlin.time.Duration.Companion.seconds @@ -31,7 +30,7 @@ internal class LoggingRepositoryImpl @Inject constructor( override fun startLogging( terminal: Terminal, startingId: Long, - ): Flow = channelFlow { + ): Flow = flow { val command = LoggingRepository.COMMAND + when (appPreferences.showLogsFromAppLaunch) { true -> LoggingRepository.SHOW_LOGS_FROM_NOW_FLAGS @@ -45,7 +44,7 @@ internal class LoggingRepositoryImpl @Inject constructor( ) }.flowOn(ioDispatcher) - override fun dumpLogs(terminal: Terminal): Flow = channelFlow { + override fun dumpLogs(terminal: Terminal): Flow = flow { val command = LoggingRepository.COMMAND + LoggingRepository.DUMP_FLAG emitLines( @@ -55,7 +54,7 @@ internal class LoggingRepositoryImpl @Inject constructor( ) }.flowOn(ioDispatcher) - private suspend fun ProducerScope.emitLines( + private suspend fun FlowCollector.emitLines( terminal: Terminal, command: Array, startingId: Long = 0, @@ -72,39 +71,32 @@ internal class LoggingRepositoryImpl @Inject constructor( Timber.d("starting with id $idsCounter") try { - val readerScope = CoroutineScope(ioDispatcher + SupervisorJob()) - invokeOnClose { readerScope.cancel() } + Timber.d("started scope") - process.output.bufferedReader().useLines { linesSequence -> + process.output.bufferedReader().use { reader -> var droppedFirst = !appPreferences.showLogsFromAppLaunch // avoiding getting the same line after logging restart because of // WARNING: -T 0 invalid, setting to 1 - val iterator = linesSequence.iterator() + Timber.d("got reader") - var looping = true - while (looping) { + while (true) { withTimeout(10.seconds) { - readerScope.launch { - if (iterator.hasNext().not()) { - looping = false - } else { - val line = iterator.next() - Timber.d("got line $line") - - val logLine = LogLine( - id = idsCounter++, - line = line, - context = context, - ) - Timber.d("successfully parsed $line to $logLine") - - if (droppedFirst.not()) { - droppedFirst = true - } else { - logLine?.let { send(it) } - } - } - }.join() + Timber.d("started awaiting line") + val line = reader.readLineCancellable() + Timber.d("got line $line") + + val logLine = LogLine( + id = idsCounter++, + line = line, + context = context, + ) + Timber.d("successfully parsed $line to $logLine") + + if (droppedFirst.not()) { + droppedFirst = true + } else { + logLine?.let { emit(it) } + } } } } @@ -115,4 +107,16 @@ internal class LoggingRepositoryImpl @Inject constructor( } } } + + private suspend fun BufferedReader.readLineCancellable(): String = withContext(ioDispatcher) { + while (true) { + yield() + + if (ready()) { + return@withContext readLine() + } + } + + "not reachable" + } } diff --git a/feature/recordings/list/src/main/kotlin/com/f0x1d/logfox/feature/recordings/list/presentation/ui/RecordingsFragment.kt b/feature/recordings/list/src/main/kotlin/com/f0x1d/logfox/feature/recordings/list/presentation/ui/RecordingsFragment.kt index 92be933c..37b75f3e 100644 --- a/feature/recordings/list/src/main/kotlin/com/f0x1d/logfox/feature/recordings/list/presentation/ui/RecordingsFragment.kt +++ b/feature/recordings/list/src/main/kotlin/com/f0x1d/logfox/feature/recordings/list/presentation/ui/RecordingsFragment.kt @@ -16,7 +16,6 @@ import com.f0x1d.logfox.feature.recordings.list.presentation.RecordingsAction import com.f0x1d.logfox.feature.recordings.list.presentation.RecordingsViewModel import com.f0x1d.logfox.feature.recordings.list.presentation.ui.compose.RecordingsScreenContent import com.f0x1d.logfox.navigation.Directions -import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme import com.f0x1d.logfox.ui.dialog.showAreYouSureClearDialog import com.f0x1d.logfox.ui.dialog.showAreYouSureDeleteDialog import dagger.hilt.android.AndroidEntryPoint @@ -63,15 +62,13 @@ class RecordingsFragment : BaseComposeFragment() { @Composable override fun Content() { - LogFoxTheme { - val state by viewModel.state.collectAsState() + val state by viewModel.state.collectAsState() - RecordingsScreenContent( - state = state, - listener = listener, - snackbarHostState = snackbarHostState, - ) - } + RecordingsScreenContent( + state = state, + listener = listener, + snackbarHostState = snackbarHostState, + ) } private fun openDetails(recording: LogRecording?) = recording?.id?.also { diff --git a/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/SetupFragment.kt b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/SetupFragment.kt index a099fc4c..b26ffc40 100644 --- a/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/SetupFragment.kt +++ b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/SetupFragment.kt @@ -12,7 +12,6 @@ import com.f0x1d.logfox.arch.presentation.ui.fragment.compose.BaseComposeFragmen import com.f0x1d.logfox.feature.setup.presentation.SetupAction import com.f0x1d.logfox.feature.setup.presentation.SetupViewModel import com.f0x1d.logfox.feature.setup.presentation.ui.compose.SetupScreenContent -import com.f0x1d.logfox.ui.compose.theme.LogFoxTheme import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch @@ -48,14 +47,12 @@ class SetupFragment : BaseComposeFragment() { @Composable override fun Content() { - LogFoxTheme { - val state by viewModel.state.collectAsState() - - SetupScreenContent( - state = state, - listener = listener, - snackbarHostState = snackbarHostState, - ) - } + val state by viewModel.state.collectAsState() + + SetupScreenContent( + state = state, + listener = listener, + snackbarHostState = snackbarHostState, + ) } } diff --git a/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/compose/SetupScreenContent.kt b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/compose/SetupScreenContent.kt index d40ff8d0..79eefca8 100644 --- a/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/compose/SetupScreenContent.kt +++ b/feature/setup/src/main/kotlin/com/f0x1d/logfox/feature/setup/presentation/ui/compose/SetupScreenContent.kt @@ -157,21 +157,17 @@ const val SetupAdbDialogTestTag = "SetupAdbDialog" @DayNightPreview @Composable -private fun SetupScreenContentPreview() { - LogFoxTheme { - SetupScreenContent() - } +private fun SetupScreenContentPreview() = LogFoxTheme { + SetupScreenContent() } @DayNightPreview @Composable -private fun SetupScreenContentWithDialogPreview() { - LogFoxTheme { - SetupScreenContent( - state = SetupState( - showAdbDialog = true, - adbCommand = "HESOYAM", - ) +private fun SetupScreenContentWithDialogPreview() = LogFoxTheme { + SetupScreenContent( + state = SetupState( + showAdbDialog = true, + adbCommand = "HESOYAM", ) - } + ) }