diff --git a/core/ui/src/androidMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt b/core/ui/src/androidMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt new file mode 100644 index 000000000..a8e59a441 --- /dev/null +++ b/core/ui/src/androidMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt @@ -0,0 +1,16 @@ +package org.michaelbel.movies.ui.ktx + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.flow.StateFlow + +@Composable +actual fun StateFlow.collectAsStateCommon( + lifecycleOwner: LifecycleOwner, + minActiveState: Lifecycle.State, + context: CoroutineContext +): State = collectAsStateWithLifecycle() \ No newline at end of file diff --git a/core/ui/src/commonMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt b/core/ui/src/commonMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt new file mode 100644 index 000000000..ebe57859a --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt @@ -0,0 +1,17 @@ +package org.michaelbel.movies.ui.ktx + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext +import kotlinx.coroutines.flow.StateFlow + +@Composable +expect fun StateFlow.collectAsStateCommon( + lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current, + minActiveState: Lifecycle.State = Lifecycle.State.STARTED, + context: CoroutineContext = EmptyCoroutineContext +): State \ No newline at end of file diff --git a/core/ui/src/desktopMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt b/core/ui/src/desktopMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt new file mode 100644 index 000000000..9a9a312e9 --- /dev/null +++ b/core/ui/src/desktopMain/kotlin/org/michaelbel/movies/ui/ktx/LifecycleKtx.kt @@ -0,0 +1,16 @@ +package org.michaelbel.movies.ui.ktx + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.flow.StateFlow + +@Composable +actual fun StateFlow.collectAsStateCommon( + lifecycleOwner: LifecycleOwner, + minActiveState: Lifecycle.State, + context: CoroutineContext +): State = collectAsState() \ No newline at end of file diff --git a/feature/feed-impl/src/androidMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt b/feature/feed-impl/src/androidMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt index 55be2d457..694c24977 100644 --- a/feature/feed-impl/src/androidMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt +++ b/feature/feed-impl/src/androidMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt @@ -3,11 +3,11 @@ package org.michaelbel.movies.feed.ui import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.compose.collectAsLazyPagingItems import org.koin.androidx.compose.koinViewModel import org.michaelbel.movies.feed.FeedViewModel import org.michaelbel.movies.persistence.database.ktx.orEmpty +import org.michaelbel.movies.ui.ktx.collectAsStateCommon @Composable fun FeedRoute( @@ -20,11 +20,11 @@ fun FeedRoute( viewModel: FeedViewModel = koinViewModel() ) { val pagingItems = viewModel.pagingDataFlow.collectAsLazyPagingItems() - val account by viewModel.account.collectAsStateWithLifecycle() - val currentFeedView by viewModel.currentFeedView.collectAsStateWithLifecycle() - val currentMovieList by viewModel.currentMovieList.collectAsStateWithLifecycle() - val notificationsPermissionRequired by viewModel.notificationsPermissionRequired.collectAsStateWithLifecycle() - val networkStatus by viewModel.networkStatus.collectAsStateWithLifecycle() + val account by viewModel.account.collectAsStateCommon() + val currentFeedView by viewModel.currentFeedView.collectAsStateCommon() + val currentMovieList by viewModel.currentMovieList.collectAsStateCommon() + val notificationsPermissionRequired by viewModel.notificationsPermissionRequired.collectAsStateCommon() + val networkStatus by viewModel.networkStatus.collectAsStateCommon() val isAuthFailureSnackbarShowed = viewModel.isAuthFailureSnackbarShowed FeedScreenContent( diff --git a/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/FeedViewModel.kt b/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/FeedViewModel.kt index bdc49d87c..1ff12a134 100644 --- a/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/FeedViewModel.kt +++ b/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/FeedViewModel.kt @@ -1,5 +1,12 @@ package org.michaelbel.movies.feed +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.runBlocking +import org.michaelbel.movies.common.list.MovieList import org.michaelbel.movies.common.viewmodel.BaseViewModel import org.michaelbel.movies.interactor.Interactor @@ -7,5 +14,10 @@ class FeedViewModel( private val interactor: Interactor ): BaseViewModel() { - + val currentMovieList: StateFlow = interactor.currentMovieList + .stateIn( + scope = viewModelScope, + started = SharingStarted.Lazily, + initialValue = runBlocking { interactor.currentMovieList.first() } + ) } \ No newline at end of file diff --git a/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt b/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt index b33e34280..d2bf33275 100644 --- a/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt +++ b/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedRoute.kt @@ -1,17 +1,11 @@ -@file:OptIn(ExperimentalMaterial3Api::class) - package org.michaelbel.movies.feed.ui -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import org.koin.compose.koinInject import org.michaelbel.movies.feed.FeedViewModel -import org.michaelbel.movies.persistence.database.entity.pojo.AccountPojo +import org.michaelbel.movies.ui.ktx.collectAsStateCommon @Composable fun FeedRoute( @@ -23,7 +17,10 @@ fun FeedRoute( modifier: Modifier = Modifier, viewModel: FeedViewModel = koinInject() ) { + val currentMovieList by viewModel.currentMovieList.collectAsStateCommon() + FeedScreenContent( + currentMovieList = currentMovieList, onNavigateToSearch = onNavigateToSearch, onNavigateToAuth = onNavigateToAuth, onNavigateToAccount = onNavigateToAccount, @@ -31,33 +28,4 @@ fun FeedRoute( onNavigateToDetails = onNavigateToDetails, modifier = modifier ) -} - -@Composable -private fun FeedScreenContent( - onNavigateToSearch: () -> Unit, - onNavigateToAuth: () -> Unit, - onNavigateToAccount: () -> Unit, - onNavigateToSettings: () -> Unit, - onNavigateToDetails: (String, Int) -> Unit, - modifier: Modifier = Modifier -) { - Scaffold( - modifier = modifier.fillMaxSize(), - topBar = { - FeedToolbar( - title = "Now Playing Movies", - account = AccountPojo.Empty, - isTmdbApiKeyEmpty = false, - topAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), - onSearchIconClick = onNavigateToSearch, - onAuthIconClick = onNavigateToAuth, - onAccountIconClick = onNavigateToAccount, - onSettingsIconClick = onNavigateToSettings - ) - }, - containerColor = MaterialTheme.colorScheme.background - ) { innerPadding -> - - } } \ No newline at end of file diff --git a/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedScreenContent.kt b/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedScreenContent.kt new file mode 100644 index 000000000..dcdcf78e2 --- /dev/null +++ b/feature/feed-impl/src/desktopMain/kotlin/org/michaelbel/movies/feed/ui/FeedScreenContent.kt @@ -0,0 +1,44 @@ +@file:OptIn(ExperimentalMaterial3Api::class) + +package org.michaelbel.movies.feed.ui + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import org.michaelbel.movies.common.list.MovieList +import org.michaelbel.movies.feed.ktx.titleText +import org.michaelbel.movies.persistence.database.entity.pojo.AccountPojo + +@Composable +internal fun FeedScreenContent( + currentMovieList: MovieList, + onNavigateToSearch: () -> Unit, + onNavigateToAuth: () -> Unit, + onNavigateToAccount: () -> Unit, + onNavigateToSettings: () -> Unit, + onNavigateToDetails: (String, Int) -> Unit, + modifier: Modifier = Modifier +) { + Scaffold( + modifier = modifier.fillMaxSize(), + topBar = { + FeedToolbar( + title = currentMovieList.titleText, + account = AccountPojo.Empty, + isTmdbApiKeyEmpty = false, + topAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), + onSearchIconClick = onNavigateToSearch, + onAuthIconClick = onNavigateToAuth, + onAccountIconClick = onNavigateToAccount, + onSettingsIconClick = onNavigateToSettings + ) + }, + containerColor = MaterialTheme.colorScheme.background + ) { innerPadding -> + + } +} \ No newline at end of file