diff --git a/common/ui/screens/src/commonMain/kotlin/app/tivi/screens/Screens.kt b/common/ui/screens/src/commonMain/kotlin/app/tivi/screens/Screens.kt index b2e677d768..fe1cb2831d 100644 --- a/common/ui/screens/src/commonMain/kotlin/app/tivi/screens/Screens.kt +++ b/common/ui/screens/src/commonMain/kotlin/app/tivi/screens/Screens.kt @@ -39,6 +39,9 @@ object SettingsScreen : TiviScreen(name = "Settings()") @CommonParcelize object DevSettingsScreen : TiviScreen(name = "DevelopmentSettings()") +@CommonParcelize +object DevLogScreen : TiviScreen(name = "DevelopmentLog()") + @CommonParcelize data class UrlScreen(val url: String) : TiviScreen(name = "UrlScreen()") { override val arguments get() = mapOf("url" to url) diff --git a/core/logging/api/build.gradle.kts b/core/logging/api/build.gradle.kts index 94b19d4a62..50871f88c0 100644 --- a/core/logging/api/build.gradle.kts +++ b/core/logging/api/build.gradle.kts @@ -5,3 +5,13 @@ plugins { id("app.tivi.kotlin.multiplatform") } + +kotlin { + sourceSets { + val commonMain by getting { + dependencies { + api(libs.kotlin.coroutines.core) + } + } + } +} diff --git a/core/logging/api/src/commonMain/kotlin/app/tivi/util/Logger.kt b/core/logging/api/src/commonMain/kotlin/app/tivi/util/Logger.kt index 90d3d40646..1800b7775f 100644 --- a/core/logging/api/src/commonMain/kotlin/app/tivi/util/Logger.kt +++ b/core/logging/api/src/commonMain/kotlin/app/tivi/util/Logger.kt @@ -4,9 +4,6 @@ package app.tivi.util interface Logger { - - fun setup(debugMode: Boolean) = Unit - fun setUserId(id: String) = Unit /** Log a verbose exception and a message with optional format args. */ diff --git a/core/logging/api/src/commonMain/kotlin/app/tivi/util/RecordingLogger.kt b/core/logging/api/src/commonMain/kotlin/app/tivi/util/RecordingLogger.kt new file mode 100644 index 0000000000..79fe5e5e1a --- /dev/null +++ b/core/logging/api/src/commonMain/kotlin/app/tivi/util/RecordingLogger.kt @@ -0,0 +1,27 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.util + +import kotlinx.coroutines.flow.StateFlow + +interface RecordingLogger : Logger { + val buffer: StateFlow> +} + +enum class Severity { + Verbose, + Debug, + Info, + Warn, + Error, + Assert, +} + +class LogMessage( + val severity: Severity, + message: () -> String, + val throwable: Throwable?, +) { + val message: String by lazy { message() } +} diff --git a/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt b/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt index 15bae38a34..6a89aa6fc6 100644 --- a/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt +++ b/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt @@ -11,7 +11,10 @@ import me.tatarka.inject.annotations.Provides actual interface LoggerPlatformComponent { @ApplicationScope @Provides - fun provideLogger(): Logger = TimberLogger + fun provideLogger( + timberLogger: TimberLogger, + recordingLogger: RecordingLogger, + ): Logger = CompositeLogger(timberLogger, recordingLogger) @Provides @IntoSet diff --git a/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/TimberLogger.kt b/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/TimberLogger.kt index 757d84f866..a7106745f5 100644 --- a/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/TimberLogger.kt +++ b/core/logging/implementation/src/androidMain/kotlin/app/tivi/util/TimberLogger.kt @@ -5,14 +5,20 @@ package app.tivi.util import android.os.Build import android.util.Log +import app.tivi.app.ApplicationInfo +import app.tivi.app.Flavor import co.touchlab.crashkios.crashlytics.CrashlyticsKotlin +import me.tatarka.inject.annotations.Inject import timber.log.Timber -internal object TimberLogger : Logger { - override fun setup(debugMode: Boolean) { - if (debugMode) { +@Inject +class TimberLogger(applicationInfo: ApplicationInfo) : Logger { + + init { + if (applicationInfo.debugBuild || applicationInfo.flavor == Flavor.Qa) { Timber.plant(TiviDebugTree()) } + try { Timber.plant(CrashlyticsTree()) } catch (e: IllegalStateException) { diff --git a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/CompositeLogger.kt b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/CompositeLogger.kt index e3f0e527cd..4ee221013e 100644 --- a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/CompositeLogger.kt +++ b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/CompositeLogger.kt @@ -3,15 +3,13 @@ package app.tivi.util -internal fun CompositeLogger(vararg loggers: Logger): Logger = CompositeLogger(loggers = loggers) +internal fun CompositeLogger( + vararg loggers: Logger?, +): Logger = CompositeLogger(loggers = loggers.filterNotNull()) private class CompositeLogger( - private val loggers: Array, + private val loggers: Collection, ) : Logger { - override fun setup(debugMode: Boolean) { - loggers.forEach { it.setup(debugMode) } - } - override fun setUserId(id: String) { loggers.forEach { it.setUserId(id) } } diff --git a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/KermitLogger.kt b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/KermitLogger.kt index b263e126df..ce237a8838 100644 --- a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/KermitLogger.kt +++ b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/KermitLogger.kt @@ -3,12 +3,22 @@ package app.tivi.util +import app.tivi.app.ApplicationInfo +import app.tivi.app.Flavor import co.touchlab.kermit.Logger as Kermit import co.touchlab.kermit.Severity - -internal object KermitLogger : Logger { - override fun setup(debugMode: Boolean) { - Kermit.setMinSeverity(if (debugMode) Severity.Debug else Severity.Error) +import me.tatarka.inject.annotations.Inject + +@Inject +class KermitLogger(applicationInfo: ApplicationInfo) : Logger { + init { + Kermit.setMinSeverity( + when { + applicationInfo.debugBuild -> Severity.Debug + applicationInfo.flavor == Flavor.Qa -> Severity.Debug + else -> Severity.Error + }, + ) } override fun v(throwable: Throwable?, message: () -> String) { diff --git a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerComponent.kt b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerComponent.kt index c570ab812c..99198de605 100644 --- a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerComponent.kt +++ b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerComponent.kt @@ -3,14 +3,13 @@ package app.tivi.util -import app.tivi.appinitializers.AppInitializer -import me.tatarka.inject.annotations.IntoSet +import app.tivi.inject.ApplicationScope import me.tatarka.inject.annotations.Provides expect interface LoggerPlatformComponent interface LoggerComponent : LoggerPlatformComponent { + @ApplicationScope @Provides - @IntoSet - fun provideLoggerInitializer(bind: LoggerInitializer): AppInitializer = bind + fun bindRecordingLogger(): RecordingLogger = RecordingLoggerImpl() } diff --git a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerInitializer.kt b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerInitializer.kt deleted file mode 100644 index b11551010f..0000000000 --- a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/LoggerInitializer.kt +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018, Google LLC, Christopher Banes and the Tivi project contributors -// SPDX-License-Identifier: Apache-2.0 - -package app.tivi.util - -import app.tivi.app.ApplicationInfo -import app.tivi.app.Flavor -import app.tivi.appinitializers.AppInitializer -import me.tatarka.inject.annotations.Inject - -@Inject -class LoggerInitializer( - private val logger: Logger, - private val applicationInfo: ApplicationInfo, -) : AppInitializer { - override fun initialize() { - logger.setup( - debugMode = when { - applicationInfo.debugBuild -> true - applicationInfo.flavor == Flavor.Qa -> true - else -> false - }, - ) - } -} diff --git a/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/RecordingLoggerImpl.kt b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/RecordingLoggerImpl.kt new file mode 100644 index 0000000000..4e568c155e --- /dev/null +++ b/core/logging/implementation/src/commonMain/kotlin/app/tivi/util/RecordingLoggerImpl.kt @@ -0,0 +1,45 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.util + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow + +internal class RecordingLoggerImpl( + private val bufferSize: Int = 50, +) : RecordingLogger { + + private val logs = ArrayDeque(bufferSize) + private val _buffer = MutableStateFlow>(logs) + + override val buffer get() = _buffer.asStateFlow() + + override fun v(throwable: Throwable?, message: () -> String) { + addLog(LogMessage(Severity.Verbose, message, throwable)) + } + + override fun d(throwable: Throwable?, message: () -> String) { + addLog(LogMessage(Severity.Debug, message, throwable)) + } + + override fun i(throwable: Throwable?, message: () -> String) { + addLog(LogMessage(Severity.Info, message, throwable)) + } + + override fun e(throwable: Throwable?, message: () -> String) { + addLog(LogMessage(Severity.Error, message, throwable)) + } + + override fun w(throwable: Throwable?, message: () -> String) { + addLog(LogMessage(Severity.Warn, message, throwable)) + } + + private fun addLog(logMessage: LogMessage) { + while (logs.size >= bufferSize) { + logs.removeFirst() + } + logs.add(logMessage) + _buffer.value = logs.toList() + } +} diff --git a/core/logging/implementation/src/iosMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt b/core/logging/implementation/src/iosMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt index 14051d36bf..504cbf4d2a 100644 --- a/core/logging/implementation/src/iosMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt +++ b/core/logging/implementation/src/iosMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt @@ -11,7 +11,9 @@ import me.tatarka.inject.annotations.Provides actual interface LoggerPlatformComponent { @Provides @ApplicationScope - fun provideLogger(): Logger = CompositeLogger(KermitLogger, CrashKIosLogger) + fun provideLogger( + kermitLogger: KermitLogger, + ): Logger = CompositeLogger(kermitLogger, CrashKIosLogger) @Provides @IntoSet diff --git a/core/logging/implementation/src/jvmMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt b/core/logging/implementation/src/jvmMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt index 16a1ae2296..17a3f9a7cb 100644 --- a/core/logging/implementation/src/jvmMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt +++ b/core/logging/implementation/src/jvmMain/kotlin/app/tivi/util/LoggerPlatformComponent.kt @@ -3,9 +3,14 @@ package app.tivi.util +import app.tivi.inject.ApplicationScope import me.tatarka.inject.annotations.Provides actual interface LoggerPlatformComponent { @Provides - fun provideLogger(): Logger = KermitLogger + @ApplicationScope + fun provideLogger( + kermitLogger: KermitLogger, + recordingLogger: RecordingLogger, + ): Logger = CompositeLogger(kermitLogger, recordingLogger) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 32c526eb36..8ebf826fbe 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -106,6 +106,8 @@ include( ":tasks", ":domain", ":shared", + ":ui:developer:log", + ":ui:developer:settings", ":ui:discover", ":ui:episode:details", ":ui:episode:track", @@ -115,8 +117,7 @@ include( ":ui:search", ":ui:show:details", ":ui:show:seasons", - ":ui:settings:settings", - ":ui:settings:developer", + ":ui:settings", ":ui:library", ":ui:account", ":ui:upnext", diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 8d660895ad..b4f57de314 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -33,6 +33,8 @@ kotlin { api(projects.common.ui.compose) api(projects.ui.account) + api(projects.ui.developer.log) + api(projects.ui.developer.settings) api(projects.ui.discover) api(projects.ui.episode.details) api(projects.ui.episode.track) @@ -44,8 +46,7 @@ kotlin { api(projects.ui.show.details) api(projects.ui.show.seasons) api(projects.ui.root) - api(projects.ui.settings.settings) - api(projects.ui.settings.developer) + api(projects.ui.settings) api(projects.ui.upnext) } } diff --git a/shared/src/commonMain/kotlin/app/tivi/inject/UiComponent.kt b/shared/src/commonMain/kotlin/app/tivi/inject/UiComponent.kt index 3969af3052..f789a31f0d 100644 --- a/shared/src/commonMain/kotlin/app/tivi/inject/UiComponent.kt +++ b/shared/src/commonMain/kotlin/app/tivi/inject/UiComponent.kt @@ -7,6 +7,7 @@ import app.tivi.account.AccountComponent import app.tivi.common.ui.resources.Locales import app.tivi.common.ui.resources.Strings import app.tivi.common.ui.resources.TiviStrings +import app.tivi.developer.log.DevLogComponent import app.tivi.episode.track.EpisodeTrackComponent import app.tivi.episodedetails.EpisodeDetailsComponent import app.tivi.home.discover.DiscoverComponent @@ -37,6 +38,7 @@ interface UiComponent : SearchComponent, SettingsComponent, DevSettingsComponent, + DevLogComponent, ShowDetailsComponent, ShowSeasonsComponent, TrendingShowsComponent, diff --git a/ui/developer/log/build.gradle.kts b/ui/developer/log/build.gradle.kts new file mode 100644 index 0000000000..fa161d4e76 --- /dev/null +++ b/ui/developer/log/build.gradle.kts @@ -0,0 +1,31 @@ +// Copyright 2023, Google LLC, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + + +plugins { + id("app.tivi.android.library") + id("app.tivi.kotlin.multiplatform") + id("app.tivi.compose") +} + +android { + namespace = "app.tivi.developer.log" +} + +kotlin { + sourceSets { + val commonMain by getting { + dependencies { + implementation(projects.core.base) + implementation(projects.core.logging.api) + implementation(projects.common.ui.compose) + + api(projects.common.ui.screens) + api(libs.circuit.foundation) + + implementation(compose.material3) + implementation(compose.animation) + } + } + } +} diff --git a/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLog.kt b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLog.kt new file mode 100644 index 0000000000..8dab340dfd --- /dev/null +++ b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLog.kt @@ -0,0 +1,134 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.developer.log + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Divider +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import app.tivi.common.compose.LocalStrings +import app.tivi.screens.DevLogScreen +import app.tivi.util.Severity +import com.moriatsushi.insetsx.systemBars +import com.slack.circuit.runtime.CircuitContext +import com.slack.circuit.runtime.screen.Screen +import com.slack.circuit.runtime.ui.Ui +import com.slack.circuit.runtime.ui.ui +import me.tatarka.inject.annotations.Inject + +@Inject +class DevLogUiFactory : Ui.Factory { + override fun create(screen: Screen, context: CircuitContext): Ui<*>? = when (screen) { + is DevLogScreen -> { + ui { state, modifier -> + DevLog(state, modifier) + } + } + + else -> null + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun DevLog( + state: DevLogUiState, + modifier: Modifier = Modifier, +) { + val eventSink = state.eventSink + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Log") }, + navigationIcon = { + IconButton(onClick = { eventSink(DevLogUiEvent.NavigateUp) }) { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = LocalStrings.current.cdNavigateUp, + ) + } + }, + windowInsets = WindowInsets.systemBars + .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top), + ) + }, + contentWindowInsets = WindowInsets.systemBars, + modifier = modifier, + ) { contentPadding -> + LazyColumn( + contentPadding = contentPadding, + verticalArrangement = Arrangement.spacedBy(2.dp), + modifier = Modifier.fillMaxWidth(), + ) { + items(state.logs) { logMessage -> + Text( + text = buildAnnotatedString { + withStyle( + style = SpanStyle( + color = when (logMessage.severity) { + Severity.Verbose -> Color.Blue + Severity.Debug -> Color.Blue + Severity.Info -> Color.Yellow + Severity.Warn -> Color.Magenta + Severity.Error -> Color.Red + Severity.Assert -> Color.Red + }, + ), + ) { + append( + when (logMessage.severity) { + Severity.Verbose -> "[V]" + Severity.Debug -> "[D]" + Severity.Info -> "[I]" + Severity.Warn -> "[W]" + Severity.Error -> "[E]" + Severity.Assert -> "[A]" + }, + ) + } + append(' ') + append(logMessage.message) + }, + fontFamily = FontFamily.Monospace, + fontSize = 13.sp, + modifier = modifier.padding(horizontal = 16.dp, vertical = 2.dp), + ) + + if (logMessage.throwable != null) { + Text( + text = logMessage.throwable.toString(), + fontFamily = FontFamily.Monospace, + fontSize = 12.sp, + modifier = modifier.padding(horizontal = 16.dp, vertical = 2.dp), + ) + } + + Divider() + } + } + } +} diff --git a/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogComponent.kt b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogComponent.kt new file mode 100644 index 0000000000..6eacad66b7 --- /dev/null +++ b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogComponent.kt @@ -0,0 +1,22 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.developer.log + +import app.tivi.inject.ActivityScope +import com.slack.circuit.runtime.presenter.Presenter +import com.slack.circuit.runtime.ui.Ui +import me.tatarka.inject.annotations.IntoSet +import me.tatarka.inject.annotations.Provides + +interface DevLogComponent { + @IntoSet + @Provides + @ActivityScope + fun bindDevLogPresenterFactory(factory: DevLogUiPresenterFactory): Presenter.Factory = factory + + @IntoSet + @Provides + @ActivityScope + fun bindDevLogUiFactoryFactory(factory: DevLogUiFactory): Ui.Factory = factory +} diff --git a/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogPresenter.kt b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogPresenter.kt new file mode 100644 index 0000000000..c12ef5f59d --- /dev/null +++ b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogPresenter.kt @@ -0,0 +1,53 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.developer.log + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import app.tivi.screens.DevLogScreen +import app.tivi.util.RecordingLogger +import com.slack.circuit.runtime.CircuitContext +import com.slack.circuit.runtime.Navigator +import com.slack.circuit.runtime.presenter.Presenter +import com.slack.circuit.runtime.screen.Screen +import me.tatarka.inject.annotations.Assisted +import me.tatarka.inject.annotations.Inject + +@Inject +class DevLogUiPresenterFactory( + private val presenterFactory: (Navigator) -> DevLogPresenter, +) : Presenter.Factory { + override fun create( + screen: Screen, + navigator: Navigator, + context: CircuitContext, + ): Presenter<*>? = when (screen) { + is DevLogScreen -> presenterFactory(navigator) + else -> null + } +} + +@Inject +class DevLogPresenter( + @Assisted private val navigator: Navigator, + private val recordingLogger: RecordingLogger, +) : Presenter { + + @Composable + override fun present(): DevLogUiState { + val logs by recordingLogger.buffer.collectAsState() + + fun eventSink(event: DevLogUiEvent) { + when (event) { + DevLogUiEvent.NavigateUp -> navigator.pop() + } + } + + return DevLogUiState( + logs = logs, + eventSink = ::eventSink, + ) + } +} diff --git a/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogUiState.kt b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogUiState.kt new file mode 100644 index 0000000000..b986a33b63 --- /dev/null +++ b/ui/developer/log/src/commonMain/kotlin/app/tivi/developer/log/DevLogUiState.kt @@ -0,0 +1,19 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.developer.log + +import androidx.compose.runtime.Immutable +import app.tivi.util.LogMessage +import com.slack.circuit.runtime.CircuitUiEvent +import com.slack.circuit.runtime.CircuitUiState + +@Immutable +data class DevLogUiState( + val logs: List, + val eventSink: (DevLogUiEvent) -> Unit, +) : CircuitUiState + +sealed interface DevLogUiEvent : CircuitUiEvent { + data object NavigateUp : DevLogUiEvent +} diff --git a/ui/settings/developer/build.gradle.kts b/ui/developer/settings/build.gradle.kts similarity index 100% rename from ui/settings/developer/build.gradle.kts rename to ui/developer/settings/build.gradle.kts diff --git a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettings.kt b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettings.kt similarity index 89% rename from ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettings.kt rename to ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettings.kt index a6aacbb5b9..af9ec1ff74 100644 --- a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettings.kt +++ b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettings.kt @@ -4,6 +4,7 @@ package app.tivi.settings.developer import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxWidth @@ -21,6 +22,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import app.tivi.common.compose.LocalStrings import app.tivi.common.compose.ui.CheckboxPreference +import app.tivi.common.compose.ui.Preference import app.tivi.screens.DevSettingsScreen import com.moriatsushi.insetsx.systemBars import com.slack.circuit.runtime.CircuitContext @@ -80,6 +82,15 @@ internal fun DevSettings( onCheckClicked = { state.eventSink(DevSettingsUiEvent.ToggleHideArtwork) }, ) } + + item { + Preference( + title = "Open log", + modifier = Modifier.clickable { + state.eventSink(DevSettingsUiEvent.NavigateLog) + }, + ) + } } } } diff --git a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsComponent.kt b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsComponent.kt similarity index 100% rename from ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsComponent.kt rename to ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsComponent.kt diff --git a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsPresenter.kt b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsPresenter.kt similarity index 93% rename from ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsPresenter.kt rename to ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsPresenter.kt index 91f76d3bcc..ef00169a93 100644 --- a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsPresenter.kt +++ b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsPresenter.kt @@ -6,6 +6,7 @@ package app.tivi.settings.developer import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import app.tivi.screens.DevLogScreen import app.tivi.screens.DevSettingsScreen import app.tivi.settings.TiviPreferences import app.tivi.settings.toggle @@ -43,6 +44,7 @@ class DevSettingsPresenter( fun eventSink(event: DevSettingsUiEvent) { when (event) { DevSettingsUiEvent.NavigateUp -> navigator.pop() + DevSettingsUiEvent.NavigateLog -> navigator.goTo(DevLogScreen) DevSettingsUiEvent.ToggleHideArtwork -> preferences::developerHideArtwork.toggle() } } diff --git a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsUiState.kt b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsUiState.kt similarity index 92% rename from ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsUiState.kt rename to ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsUiState.kt index c5711ca437..8f7151246b 100644 --- a/ui/settings/developer/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsUiState.kt +++ b/ui/developer/settings/src/commonMain/kotlin/app/tivi/settings/developer/DevSettingsUiState.kt @@ -15,5 +15,6 @@ data class DevSettingsUiState( sealed interface DevSettingsUiEvent : CircuitUiEvent { data object NavigateUp : DevSettingsUiEvent + data object NavigateLog : DevSettingsUiEvent data object ToggleHideArtwork : DevSettingsUiEvent } diff --git a/ui/settings/settings/build.gradle.kts b/ui/settings/build.gradle.kts similarity index 100% rename from ui/settings/settings/build.gradle.kts rename to ui/settings/build.gradle.kts diff --git a/ui/settings/settings/src/androidMain/kotlin/app/tivi/settings/Platform.kt b/ui/settings/src/androidMain/kotlin/app/tivi/settings/Platform.kt similarity index 100% rename from ui/settings/settings/src/androidMain/kotlin/app/tivi/settings/Platform.kt rename to ui/settings/src/androidMain/kotlin/app/tivi/settings/Platform.kt diff --git a/ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/Platform.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/Platform.kt similarity index 100% rename from ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/Platform.kt rename to ui/settings/src/commonMain/kotlin/app/tivi/settings/Platform.kt diff --git a/ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt similarity index 100% rename from ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt rename to ui/settings/src/commonMain/kotlin/app/tivi/settings/Settings.kt diff --git a/ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/SettingsComponent.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsComponent.kt similarity index 100% rename from ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/SettingsComponent.kt rename to ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsComponent.kt diff --git a/ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt similarity index 100% rename from ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt rename to ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsPresenter.kt diff --git a/ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt b/ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt similarity index 100% rename from ui/settings/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt rename to ui/settings/src/commonMain/kotlin/app/tivi/settings/SettingsUiState.kt diff --git a/ui/settings/settings/src/iosMain/kotlin/app/tivi/settings/Platform.kt b/ui/settings/src/iosMain/kotlin/app/tivi/settings/Platform.kt similarity index 100% rename from ui/settings/settings/src/iosMain/kotlin/app/tivi/settings/Platform.kt rename to ui/settings/src/iosMain/kotlin/app/tivi/settings/Platform.kt diff --git a/ui/settings/settings/src/jvmMain/kotlin/app/tivi/settings/Platform.kt b/ui/settings/src/jvmMain/kotlin/app/tivi/settings/Platform.kt similarity index 100% rename from ui/settings/settings/src/jvmMain/kotlin/app/tivi/settings/Platform.kt rename to ui/settings/src/jvmMain/kotlin/app/tivi/settings/Platform.kt