From cf60cbbbce08a0e54693c25a538aa1de4ead2285 Mon Sep 17 00:00:00 2001 From: Chris Banes Date: Wed, 28 Jun 2023 22:34:52 +0100 Subject: [PATCH] Move Home() and TiviContent() to :ui:root --- android-app/app/build.gradle.kts | 21 +---- .../main/kotlin/app/tivi/home/MainActivity.kt | 92 +++---------------- settings.gradle.kts | 1 + shared/build.gradle.kts | 1 + ui/root/build.gradle.kts | 35 +++++++ .../commonMain}/kotlin/app/tivi/home/Home.kt | 12 +-- .../kotlin/app/tivi/home/TiviContent.kt | 92 +++++++++++++++++++ 7 files changed, 150 insertions(+), 104 deletions(-) create mode 100644 ui/root/build.gradle.kts rename {android-app/app/src/main => ui/root/src/commonMain}/kotlin/app/tivi/home/Home.kt (95%) create mode 100644 ui/root/src/commonMain/kotlin/app/tivi/home/TiviContent.kt diff --git a/android-app/app/build.gradle.kts b/android-app/app/build.gradle.kts index 8254756123..168cd48cd2 100644 --- a/android-app/app/build.gradle.kts +++ b/android-app/app/build.gradle.kts @@ -148,37 +148,22 @@ androidComponents { dependencies { implementation(projects.shared) - - implementation(projects.ui.account) implementation(projects.ui.settings) - implementation(libs.circuit.overlay) - - implementation(libs.androidx.lifecycle.viewmodel.ktx) - implementation(libs.androidx.activity.activity) implementation(libs.androidx.activity.compose) - implementation(libs.androidx.emoji) - - implementation(compose.foundation) - implementation(compose.material) - implementation(compose.materialIconsExtended) - implementation(compose.material3) - implementation(libs.compose.material3.windowsizeclass) - implementation(compose.animation) - implementation(compose.uiTooling) + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.androidx.profileinstaller) implementation(libs.kotlin.coroutines.android) - implementation(libs.androidx.profileinstaller) + implementation(libs.google.firebase.crashlytics) implementation(libs.okhttp.loggingInterceptor) ksp(libs.kotlininject.compiler) - implementation(libs.google.firebase.crashlytics) - qaImplementation(libs.chucker.library) qaImplementation(libs.debugdrawer.debugdrawer) diff --git a/android-app/app/src/main/kotlin/app/tivi/home/MainActivity.kt b/android-app/app/src/main/kotlin/app/tivi/home/MainActivity.kt index 20e33e95c8..5dd32714a2 100644 --- a/android-app/app/src/main/kotlin/app/tivi/home/MainActivity.kt +++ b/android-app/app/src/main/kotlin/app/tivi/home/MainActivity.kt @@ -8,13 +8,12 @@ import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.viewModels -import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi -import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass -import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.remember +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.core.view.WindowCompat import androidx.lifecycle.findViewTreeLifecycleOwner import androidx.lifecycle.findViewTreeViewModelStoreOwner @@ -27,35 +26,20 @@ import app.tivi.ContentViewSetter import app.tivi.TiviActivity import app.tivi.common.compose.LocalTiviDateFormatter import app.tivi.common.compose.LocalTiviTextCreator -import app.tivi.common.compose.LocalWindowSizeClass -import app.tivi.common.compose.shouldUseDarkColors -import app.tivi.common.compose.shouldUseDynamicColors -import app.tivi.common.compose.theme.TiviTheme import app.tivi.core.analytics.Analytics import app.tivi.data.traktauth.LoginToTraktInteractor import app.tivi.data.traktauth.TraktAuthActivityComponent import app.tivi.inject.ActivityComponent import app.tivi.inject.ActivityScope import app.tivi.inject.AndroidApplicationComponent -import app.tivi.overlays.LocalNavigator -import app.tivi.screens.DiscoverScreen -import app.tivi.screens.SettingsScreen -import app.tivi.screens.TiviScreen import app.tivi.settings.SettingsActivity import app.tivi.settings.TiviPreferences import app.tivi.util.TiviDateFormatter import app.tivi.util.TiviTextCreator import com.seiko.imageloader.ImageLoader import com.seiko.imageloader.LocalImageLoader -import com.slack.circuit.backstack.SaveableBackStack -import com.slack.circuit.backstack.rememberSaveableBackStack import com.slack.circuit.foundation.CircuitCompositionLocals import com.slack.circuit.foundation.CircuitConfig -import com.slack.circuit.foundation.push -import com.slack.circuit.foundation.rememberCircuitNavigator -import com.slack.circuit.foundation.screen -import com.slack.circuit.runtime.Navigator -import com.slack.circuit.runtime.Screen import me.tatarka.inject.annotations.Component import me.tatarka.inject.annotations.Provides @@ -69,6 +53,7 @@ class MainActivity : TiviActivity() { } } + @OptIn(ExperimentalComposeUiApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) component = MainActivityComponent::class.create(this) @@ -89,9 +74,19 @@ class MainActivity : TiviActivity() { TiviContent( analytics = component.analytics, preferences = component.preferences, + onRootPop = { + if (onBackPressedDispatcher.hasEnabledCallbacks()) { + onBackPressedDispatcher.onBackPressed() + } + }, onOpenSettings = { context.startActivity(Intent(context, SettingsActivity::class.java)) }, + modifier = Modifier.semantics { + // Enables testTag -> UiAutomator resource id + // See https://developer.android.com/jetpack/compose/testing#uiautomator-interop + testTagsAsResourceId = true + }, ) } } @@ -108,63 +103,6 @@ class MainActivity : TiviActivity() { } } -@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -@Composable -private fun TiviContent( - onOpenSettings: () -> Unit, - analytics: Analytics, - preferences: TiviPreferences, -) { - val backstack: SaveableBackStack = rememberSaveableBackStack { push(DiscoverScreen) } - val circuitNavigator = rememberCircuitNavigator(backstack) - - val navigator: Navigator = remember(circuitNavigator) { - TiviNavigator(circuitNavigator, onOpenSettings) - } - - // Launch an effect to track changes to the current back stack entry, and push them - // as a screen views to analytics - LaunchedEffect(backstack.topRecord) { - val topScreen = backstack.topRecord?.screen as? TiviScreen - analytics.trackScreenView( - name = topScreen?.name ?: "unknown screen", - arguments = topScreen?.arguments, - ) - } - - CompositionLocalProvider( - LocalNavigator provides navigator, - LocalWindowSizeClass provides calculateWindowSizeClass(), - ) { - TiviTheme( - useDarkColors = preferences.shouldUseDarkColors(), - useDynamicColors = preferences.shouldUseDynamicColors(), - ) { - Home(backstack = backstack, navigator = navigator) - } - } -} - -private class TiviNavigator( - private val navigator: Navigator, - private val onOpenSettings: () -> Unit, -) : Navigator { - override fun goTo(screen: Screen) { - when (screen) { - is SettingsScreen -> onOpenSettings() - else -> navigator.goTo(screen) - } - } - - override fun pop(): Screen? { - return navigator.pop() - } - - override fun resetRoot(newRoot: Screen): List { - return navigator.resetRoot(newRoot) - } -} - @ActivityScope @Component abstract class MainActivityComponent( diff --git a/settings.gradle.kts b/settings.gradle.kts index f12ca9c51e..04beaeb66a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -95,6 +95,7 @@ include( ":ui:library", ":ui:account", ":ui:upnext", + ":ui:root", ":android-app:app", ":android-app:benchmark", ":android-app:common-test", diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index b7e9791a56..6c13dbb17c 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -48,6 +48,7 @@ kotlin { api(projects.ui.search) api(projects.ui.show.details) api(projects.ui.show.seasons) + api(projects.ui.root) // api(projects.ui.settings) api(projects.ui.upnext) } diff --git a/ui/root/build.gradle.kts b/ui/root/build.gradle.kts new file mode 100644 index 0000000000..07d2178b72 --- /dev/null +++ b/ui/root/build.gradle.kts @@ -0,0 +1,35 @@ +// 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") + alias(libs.plugins.composeMultiplatform) +} + +android { + namespace = "app.tivi.home" +} + +kotlin { + sourceSets { + val commonMain by getting { + dependencies { + implementation(projects.core.base) + implementation(projects.core.analytics) + implementation(projects.common.ui.compose) + + implementation(projects.common.ui.screens) + implementation(libs.circuit.foundation) + implementation(libs.circuit.overlay) + implementation(projects.common.ui.circuitOverlay) + + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.materialIconsExtended) + implementation(compose.animation) + } + } + } +} diff --git a/android-app/app/src/main/kotlin/app/tivi/home/Home.kt b/ui/root/src/commonMain/kotlin/app/tivi/home/Home.kt similarity index 95% rename from android-app/app/src/main/kotlin/app/tivi/home/Home.kt rename to ui/root/src/commonMain/kotlin/app/tivi/home/Home.kt index 3664a024d4..87d798325a 100644 --- a/android-app/app/src/main/kotlin/app/tivi/home/Home.kt +++ b/ui/root/src/commonMain/kotlin/app/tivi/home/Home.kt @@ -42,11 +42,8 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.unit.dp import app.tivi.common.compose.LocalWindowSizeClass import app.tivi.common.ui.resources.MR @@ -66,11 +63,12 @@ import com.slack.circuit.runtime.Screen import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.compose.stringResource -@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class) @Composable internal fun Home( backstack: SaveableBackStack, navigator: Navigator, + modifier: Modifier = Modifier, ) { val windowSizeClass = LocalWindowSizeClass.current val navigationType = remember(windowSizeClass) { @@ -99,11 +97,7 @@ internal fun Home( }, contentWindowInsets = ScaffoldDefaults.contentWindowInsets .exclude(WindowInsets.statusBars), // We let content handle the status bar - modifier = Modifier.semantics { - // Enables testTag -> UiAutomator resource id - // See https://developer.android.com/jetpack/compose/testing#uiautomator-interop - testTagsAsResourceId = true - }, + modifier = modifier, ) { paddingValues -> Row( modifier = Modifier diff --git a/ui/root/src/commonMain/kotlin/app/tivi/home/TiviContent.kt b/ui/root/src/commonMain/kotlin/app/tivi/home/TiviContent.kt new file mode 100644 index 0000000000..0c16b5c734 --- /dev/null +++ b/ui/root/src/commonMain/kotlin/app/tivi/home/TiviContent.kt @@ -0,0 +1,92 @@ +// Copyright 2023, Christopher Banes and the Tivi project contributors +// SPDX-License-Identifier: Apache-2.0 + +package app.tivi.home + +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import app.tivi.common.compose.LocalWindowSizeClass +import app.tivi.common.compose.shouldUseDarkColors +import app.tivi.common.compose.shouldUseDynamicColors +import app.tivi.common.compose.theme.TiviTheme +import app.tivi.core.analytics.Analytics +import app.tivi.overlays.LocalNavigator +import app.tivi.screens.DiscoverScreen +import app.tivi.screens.SettingsScreen +import app.tivi.screens.TiviScreen +import app.tivi.settings.TiviPreferences +import com.slack.circuit.backstack.SaveableBackStack +import com.slack.circuit.backstack.rememberSaveableBackStack +import com.slack.circuit.foundation.push +import com.slack.circuit.foundation.rememberCircuitNavigator +import com.slack.circuit.foundation.screen +import com.slack.circuit.runtime.Navigator +import com.slack.circuit.runtime.Screen + +@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) +@Composable +fun TiviContent( + onRootPop: () -> Unit, + onOpenSettings: () -> Unit, + analytics: Analytics, + preferences: TiviPreferences, + modifier: Modifier = Modifier, +) { + val backstack: SaveableBackStack = rememberSaveableBackStack { push(DiscoverScreen) } + val circuitNavigator = rememberCircuitNavigator(backstack, onRootPop) + + val navigator: Navigator = remember(circuitNavigator) { + TiviNavigator(circuitNavigator, onOpenSettings) + } + + // Launch an effect to track changes to the current back stack entry, and push them + // as a screen views to analytics + LaunchedEffect(backstack.topRecord) { + val topScreen = backstack.topRecord?.screen as? TiviScreen + analytics.trackScreenView( + name = topScreen?.name ?: "unknown screen", + arguments = topScreen?.arguments, + ) + } + + CompositionLocalProvider( + LocalNavigator provides navigator, + LocalWindowSizeClass provides calculateWindowSizeClass(), + ) { + TiviTheme( + useDarkColors = preferences.shouldUseDarkColors(), + useDynamicColors = preferences.shouldUseDynamicColors(), + ) { + Home( + backstack = backstack, + navigator = navigator, + modifier = modifier, + ) + } + } +} + +private class TiviNavigator( + private val navigator: Navigator, + private val onOpenSettings: () -> Unit, +) : Navigator { + override fun goTo(screen: Screen) { + when (screen) { + is SettingsScreen -> onOpenSettings() + else -> navigator.goTo(screen) + } + } + + override fun pop(): Screen? { + return navigator.pop() + } + + override fun resetRoot(newRoot: Screen): List { + return navigator.resetRoot(newRoot) + } +}