From 40097b2238b3100df15167bae3a7eafb26c4ee2c Mon Sep 17 00:00:00 2001 From: stslex Date: Sun, 19 May 2024 16:17:38 +0300 Subject: [PATCH] fix initial state problems --- .../core/ui/mvi/BaseViewModel.kt | 28 +++++++------- .../navigation/SingleCollectionGraph.kt | 6 +-- .../ui/presenter/SingleCollectionStore.kt | 12 ++++-- .../ui/presenter/SingleCollectionViewModel.kt | 21 ++++++----- .../favourite/navigation/FavouriteGraph.kt | 13 +++++-- .../favourite/ui/presenter/FavouriteStore.kt | 14 +++++-- .../ui/presenter/FavouriteViewModel.kt | 37 ++++++++++--------- .../feature/home/navigation/HomeGraph.kt | 25 ++++++++----- .../feature/home/ui/presenter/HomeStore.kt | 17 +++++++-- .../home/ui/presenter/HomeViewModel.kt | 28 +++++++++----- .../ui/presenter/ImageDetailStore.kt | 10 ++++- .../ui/presenter/ImageDetailViewModel.kt | 14 +++---- .../search/navigation/SearchPhotosGraph.kt | 9 ++++- .../search/ui/presenter/SearchStore.kt | 15 ++++++-- .../search/ui/presenter/SearchViewModel.kt | 36 ++++++++++-------- .../feature/user/navigation/UserGraph.kt | 9 +++-- .../ui/components/header/UserBioComponent.kt | 4 +- .../feature/user/ui/presenter/UserStore.kt | 18 ++++++--- .../user/ui/presenter/UserViewModel.kt | 37 +++++++++++++------ 19 files changed, 224 insertions(+), 129 deletions(-) diff --git a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt index 1ac86d33..defa4126 100644 --- a/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt +++ b/core/ui/src/main/java/st/slex/csplashscreen/core/ui/mvi/BaseViewModel.kt @@ -31,21 +31,17 @@ import st.slex.csplashscreen.core.ui.mvi.Store.State abstract class BaseViewModel( private val router: Router, - private val appDispatcher: AppDispatcher + private val appDispatcher: AppDispatcher, + initialState: S ) : ViewModel() { - abstract val initialState: S - abstract fun sendAction(action: A) - - protected open val _state: MutableStateFlow = MutableStateFlow(initialState) + private val _state: MutableStateFlow = MutableStateFlow(initialState) val state: StateFlow get() = _state.asStateFlow() val event: MutableSharedFlow = MutableSharedFlow() - fun updateState(update: (S) -> S) { - _state.update(update) - } + abstract fun sendAction(action: A) fun sendEvent(event: E) { viewModelScope.launch(appDispatcher.default) { @@ -53,18 +49,22 @@ abstract class BaseViewModel( } } - fun navigate(event: N) { + protected fun navigate(event: N) { router(event) } - fun Pager.state( + protected fun updateState(update: (S) -> S) { + _state.update(update) + } + + protected fun Pager.state( transform: suspend (value: T) -> R ): StateFlow> = this .flow .map { pagingData -> pagingData.map(transform) } .state() - fun Flow>.state(): StateFlow> = this + protected fun Flow>.state(): StateFlow> = this .flowOn(appDispatcher.default) .cachedIn(viewModelScope) .stateIn( @@ -73,14 +73,14 @@ abstract class BaseViewModel( started = SharingStarted.Lazily ) - fun launch( + protected fun launch( block: suspend CoroutineScope.() -> Unit ): Job = viewModelScope.launch( context = appDispatcher.default, block = block ) - fun launchCatching( + protected fun launchCatching( block: suspend CoroutineScope.() -> T, onFailure: suspend (Throwable) -> Unit = {}, onSuccess: (T) -> Unit, @@ -95,7 +95,7 @@ abstract class BaseViewModel( } } - fun Flow.launch( + protected fun Flow.launch( onError: suspend (cause: Throwable) -> Unit = {}, each: suspend (T) -> Unit ): Job = this diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt index 391505ed..cdc0868b 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/navigation/SingleCollectionGraph.kt @@ -1,12 +1,11 @@ package st.slex.csplashscreen.feature.collection.navigation import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems +import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState import st.slex.csplashscreen.core.navigation.AppArguments import st.slex.csplashscreen.core.navigation.AppDestination import st.slex.csplashscreen.core.ui.base.createScreen @@ -24,8 +23,7 @@ fun NavGraphBuilder.singleCollectionGraph( featureBuilder = SingleCollectionBuilder ) { viewModel: SingleCollectionViewModel, args -> val arguments = args.first().let(AppArguments::CollectionScreen) - val state by remember { viewModel.state }.collectAsState() - val photos = remember { state.photos() }.collectAsLazyPagingItems() + val photos = remember { viewModel.state.mapState { it.photos } }.collectAsLazyPagingItems() LaunchedEffect(Unit) { viewModel.sendAction(Action.Init(arguments.collectionId)) diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt index 9ecfeac3..4e722cb8 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionStore.kt @@ -2,7 +2,6 @@ package st.slex.csplashscreen.feature.collection.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.Store @@ -10,9 +9,16 @@ interface SingleCollectionStore { @Stable data class State( - val photos: () -> StateFlow>, + val photos: PagingData, val collectionId: String, - ) : Store.State + ) : Store.State { + companion object { + val INITIAL = State( + photos = PagingData.empty(), + collectionId = "" + ) + } + } @Stable sealed interface Event : Store.Event diff --git a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt index b8dcbf95..393aa8b7 100644 --- a/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt +++ b/feature/collection/src/main/java/st/slex/csplashscreen/feature/collection/ui/presenter/SingleCollectionViewModel.kt @@ -5,7 +5,6 @@ import androidx.paging.PagingConfig import androidx.paging.PagingData import androidx.paging.map import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest @@ -28,14 +27,11 @@ class SingleCollectionViewModel @Inject constructor( private val interactor: SingleCollectionInteractor, appDispatcher: AppDispatcher, router: SingleCollectionRouter -) : BaseViewModel(router, appDispatcher) { - - override val initialState: State = State( - photos = ::allPhotos, - collectionId = "" - ) - - override val _state: MutableStateFlow = MutableStateFlow(initialState) +) : BaseViewModel( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { override fun sendAction(action: Action) { when (action) { @@ -51,6 +47,13 @@ class SingleCollectionViewModel @Inject constructor( collectionId = action.collectionId ) } + allPhotos.launch { pagingData -> + updateState { currentState -> + currentState.copy( + photos = pagingData + ) + } + } } @OptIn(ExperimentalCoroutinesApi::class) diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt index 4b0e1624..611ec096 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/navigation/FavouriteGraph.kt @@ -1,11 +1,11 @@ package st.slex.csplashscreen.feature.favourite.navigation -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems +import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState import st.slex.csplashscreen.core.navigation.AppDestination import st.slex.csplashscreen.core.ui.base.createScreen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent @@ -21,9 +21,14 @@ fun NavGraphBuilder.favouriteGraph( appDestination = AppDestination.FAVOURITE, featureBuilder = FavouriteComponentBuilder ) { viewModel: FavouriteViewModel, _ -> - val state by remember { viewModel.state }.collectAsState() - val photos = remember(state.photos).collectAsLazyPagingItems() + LaunchedEffect(Unit) { + viewModel.sendAction(Action.Init) + } + + val photos = remember { + viewModel.state.mapState { it.photos } + }.collectAsLazyPagingItems() viewModel.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt index 0b3018b7..73be1026 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteStore.kt @@ -2,7 +2,6 @@ package st.slex.csplashscreen.feature.favourite.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.Store @@ -10,8 +9,15 @@ interface FavouriteStore : Store { @Stable data class State( - val photos: () -> StateFlow> - ) : Store.State + val photos: PagingData + ) : Store.State { + + companion object { + val INITIAL = State( + photos = PagingData.empty() + ) + } + } @Stable sealed interface Event : Store.Event @@ -36,6 +42,8 @@ interface FavouriteStore : Store { @Stable sealed interface Action : Store.Action { + data object Init : Action + data class OnUserClick( val username: String ) : Action diff --git a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt index 55fe146f..0eb8ceea 100644 --- a/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt +++ b/feature/favourite/src/main/java/st/slex/csplashscreen/feature/favourite/ui/presenter/FavouriteViewModel.kt @@ -1,11 +1,7 @@ package st.slex.csplashscreen.feature.favourite.ui.presenter -import androidx.paging.PagingData -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import st.slex.csplashscreen.core.core.coroutine.AppDispatcher -import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.BaseViewModel import st.slex.csplashscreen.feature.favourite.domain.FavouriteInteractor import st.slex.csplashscreen.feature.favourite.navigation.FavouriteRouter @@ -19,29 +15,34 @@ class FavouriteViewModel @Inject constructor( private val interactor: FavouriteInteractor, appDispatcher: AppDispatcher, router: FavouriteRouter -) : BaseViewModel(router, appDispatcher) { - - override val initialState: State = State( - photos = ::photos - ) - - override val _state: MutableStateFlow = MutableStateFlow(initialState) - - private val photos: StateFlow> - get() = interactor.photos - .map { pagingData -> - pagingData - } - .state() +) : BaseViewModel( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { override fun sendAction(action: Action) { when (action) { + is Action.Init -> actionInit() is Action.GoToPhotosClick -> actionGoHome() is Action.OnImageClick -> actionImageClick(action) is Action.OnUserClick -> actionUserClick(action) } } + private fun actionInit() { + interactor.photos + .map { pagingData -> + pagingData + } + .state() + .launch { data -> + updateState { state -> + state.copy(photos = data) + } + } + } + private fun actionGoHome() { navigate(Navigation.Home) } diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt index 5e0bb4f9..6b782b92 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/navigation/HomeGraph.kt @@ -1,17 +1,17 @@ package st.slex.csplashscreen.feature.home.navigation -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems +import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState import st.slex.csplashscreen.core.navigation.AppDestination import st.slex.csplashscreen.core.ui.base.createScreen import st.slex.csplashscreen.core.ui.utils.CollectAsEvent import st.slex.csplashscreen.feature.home.di.HomeComponentBuilder import st.slex.csplashscreen.feature.home.ui.MainScreen -import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore +import st.slex.csplashscreen.feature.home.ui.presenter.HomeStore.Action import st.slex.csplashscreen.feature.home.ui.presenter.HomeViewModel fun NavGraphBuilder.homeGraph( @@ -22,10 +22,17 @@ fun NavGraphBuilder.homeGraph( featureBuilder = HomeComponentBuilder ) { viewModel: HomeViewModel, _ -> - val state by remember { viewModel.state }.collectAsState() + LaunchedEffect(Unit) { + viewModel.sendAction(Action.Init) + } + + val collections = remember { + viewModel.state.mapState { it.collections } + }.collectAsLazyPagingItems() - val collections = remember(state.collections).collectAsLazyPagingItems() - val photos = remember(state.photos).collectAsLazyPagingItems() + val photos = remember { + viewModel.state.mapState { it.photos } + }.collectAsLazyPagingItems() viewModel.event.CollectAsEvent { event -> // TODO NOT IMPLEMENTED YET @@ -35,17 +42,17 @@ fun NavGraphBuilder.homeGraph( modifier = modifier, navToProfile = remember { { username -> - viewModel.sendAction(HomeStore.Action.OnUserClick(username)) + viewModel.sendAction(Action.OnUserClick(username)) } }, navToCollection = remember { { uuid -> - viewModel.sendAction(HomeStore.Action.OnCollectionClick(uuid)) + viewModel.sendAction(Action.OnCollectionClick(uuid)) } }, navToImage = remember { { uuid -> - viewModel.sendAction(HomeStore.Action.OnImageClick(uuid)) + viewModel.sendAction(Action.OnImageClick(uuid)) } }, collections = remember { collections }, diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt index 4f741257..4802e085 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeStore.kt @@ -2,7 +2,6 @@ package st.slex.csplashscreen.feature.home.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.collection.ui.model.CollectionModel import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.Store @@ -11,9 +10,17 @@ interface HomeStore : Store { @Stable data class State( - val collections: () -> StateFlow>, - val photos: () -> StateFlow> - ) : Store.State + val collections: PagingData, + val photos: PagingData + ) : Store.State { + + companion object { + val INIT = State( + collections = PagingData.empty(), + photos = PagingData.empty() + ) + } + } @Stable sealed interface Event : Store.Event @@ -40,6 +47,8 @@ interface HomeStore : Store { @Stable sealed interface Action : Store.Action { + data object Init : Action + @Stable data class OnUserClick( val username: String diff --git a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt index 5a99db40..481b67bf 100644 --- a/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt +++ b/feature/home/src/main/java/st/slex/csplashscreen/feature/home/ui/presenter/HomeViewModel.kt @@ -3,7 +3,6 @@ package st.slex.csplashscreen.feature.home.ui.presenter import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.collection.ui.model.CollectionModel import st.slex.csplashscreen.core.collection.ui.model.toPresentation @@ -24,14 +23,11 @@ class HomeViewModel @Inject constructor( private val interactor: HomeInteractor, appDispatcher: AppDispatcher, router: HomeRouter -) : BaseViewModel(router, appDispatcher) { - - override val initialState: State = State( - collections = ::collections, - photos = ::photos - ) - - override val _state: MutableStateFlow = MutableStateFlow(initialState) +) : BaseViewModel( + router = router, + appDispatcher = appDispatcher, + initialState = State.INIT +) { private val collections: StateFlow> get() = Pager(config = config) { PagingSource(interactor::getAllCollections) } @@ -43,12 +39,26 @@ class HomeViewModel @Inject constructor( override fun sendAction(action: Action) { when (action) { + is Action.Init -> actionInit() is Action.OnCollectionClick -> actionCollectionClick(action) is Action.OnImageClick -> actionImageClick(action) is Action.OnUserClick -> actionUserClick(action) } } + private fun actionInit() { + collections.launch { data -> + updateState { currentState -> + currentState.copy(collections = data) + } + } + photos.launch { data -> + updateState { currentState -> + currentState.copy(photos = data) + } + } + } + private fun actionCollectionClick(action: Action.OnCollectionClick) { navigate(Navigation.Collection(action.uuid)) } diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt index bedf7d5f..1b8c4243 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailStore.kt @@ -11,7 +11,15 @@ interface ImageDetailStore : Store { data class State( val imageId: String, val screenState: ScreenState - ) : Store.State + ) : Store.State { + + companion object { + val INITIAL: State = State( + imageId = "", + screenState = ScreenState.Loading + ) + } + } @Stable sealed interface ScreenState { diff --git a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt index 90b0f8d5..1174a480 100644 --- a/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt +++ b/feature/photo-detail/src/main/java/st/slex/csplashscreen/feature/feature_photo_detail/ui/presenter/ImageDetailViewModel.kt @@ -1,6 +1,5 @@ package st.slex.csplashscreen.feature.feature_photo_detail.ui.presenter -import kotlinx.coroutines.flow.MutableStateFlow import st.slex.csplashscreen.core.core.Logger import st.slex.csplashscreen.core.core.coroutine.AppDispatcher import st.slex.csplashscreen.core.ui.mvi.BaseViewModel @@ -26,14 +25,11 @@ class ImageDetailViewModel @Inject constructor( private val wallpaperSetUseCase: WallpaperSetUseCase, appDispatcher: AppDispatcher, router: ImageDetailRouter -) : BaseViewModel(router, appDispatcher) { - - override val initialState: State = State( - imageId = "", - screenState = ScreenState.Loading - ) - - override val _state: MutableStateFlow = MutableStateFlow(initialState) +) : BaseViewModel( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { override fun sendAction(action: Action) { when (action) { diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt index d7bb720f..2bfaac5a 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/navigation/SearchPhotosGraph.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems +import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState import st.slex.csplashscreen.core.navigation.AppArguments import st.slex.csplashscreen.core.navigation.AppDestination import st.slex.csplashscreen.core.ui.base.createScreen @@ -26,8 +27,12 @@ fun NavGraphBuilder.searchPhotosGraph( val arguments = args.firstOrNull().orEmpty().let(AppArguments::SearchPhotosScreen) val state by remember { viewModel.state }.collectAsState() - val photos = remember(state.searchItems).collectAsLazyPagingItems() - val searchHistory = remember(state.historyItems).collectAsLazyPagingItems() + val photos = remember { + viewModel.state.mapState { it.searchItems } + }.collectAsLazyPagingItems() + val searchHistory = remember { + viewModel.state.mapState { it.historyItems } + }.collectAsLazyPagingItems() LaunchedEffect(arguments) { viewModel.sendAction(Action.Init(arguments)) diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt index 670af1c0..87ecb926 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchStore.kt @@ -2,7 +2,6 @@ package st.slex.csplashscreen.feature.search.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.navigation.AppArguments import st.slex.csplashscreen.core.photos.ui.model.PhotoModel import st.slex.csplashscreen.core.ui.mvi.Store @@ -13,9 +12,17 @@ interface SearchStore { @Stable data class State( val query: String, - val historyItems: () -> StateFlow>, - val searchItems: () -> StateFlow> - ) : Store.State + val historyItems: PagingData, + val searchItems: PagingData + ) : Store.State { + companion object { + val INITIAL = State( + query = "", + historyItems = PagingData.empty(), + searchItems = PagingData.empty() + ) + } + } @Stable sealed interface Event : Store.Event diff --git a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt index 20e2475e..4334f4c1 100644 --- a/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt +++ b/feature/search/src/main/java/st/slex/csplashscreen/feature/search/ui/presenter/SearchViewModel.kt @@ -30,15 +30,11 @@ class SearchViewModel @Inject constructor( private val interactor: SearchPhotosInteractor, appDispatcher: AppDispatcher, router: SearchPhotosRouter -) : BaseViewModel(router, appDispatcher) { - - override val initialState = State( - query = "", - searchItems = ::photosSearch, - historyItems = ::searchHistory - ) - - override val _state: MutableStateFlow = MutableStateFlow(initialState) +) : BaseViewModel( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { private val searchHistory: StateFlow> get() = interactor.searchHistory.state() @@ -63,6 +59,22 @@ class SearchViewModel @Inject constructor( } } + private fun actionInit(action: Action.Init) { + updateState { currentState -> + currentState.copy(query = action.args.checkedQuery) + } + searchHistory.launch { data -> + updateState { currentState -> + currentState.copy(historyItems = data) + } + } + photosSearch.launch { data -> + updateState { currentState -> + currentState.copy(searchItems = data) + } + } + } + private fun newPagerPhotosSearch( query: String ): Pager = Pager(config) { @@ -105,12 +117,6 @@ class SearchViewModel @Inject constructor( } } - private fun actionInit(action: Action.Init) { - updateState { currentState -> - currentState.copy(query = action.args.checkedQuery) - } - } - companion object { private val config = PagingConfig( pageSize = 3, diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt index faf84440..5943c3b1 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/navigation/UserGraph.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.navigation.NavGraphBuilder import androidx.paging.compose.collectAsLazyPagingItems +import st.slex.csplashscreen.core.core.coroutine.CoroutineExt.mapState import st.slex.csplashscreen.core.navigation.AppArguments import st.slex.csplashscreen.core.navigation.AppDestination import st.slex.csplashscreen.core.ui.base.createScreen @@ -35,16 +36,16 @@ fun NavGraphBuilder.userGraph( val state by remember { viewModel.state }.collectAsState() - val photos = remember(arguments) { - state.photos(arguments.username) + val photos = remember { + viewModel.state.mapState { it.photos } }.collectAsLazyPagingItems() val likes = remember(arguments) { - state.likes(arguments.username) + viewModel.state.mapState { it.likes } }.collectAsLazyPagingItems() val collections = remember(arguments) { - state.collections(arguments.username) + viewModel.state.mapState { it.collections } }.collectAsLazyPagingItems() LaunchedEffect(arguments) { diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/components/header/UserBioComponent.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/components/header/UserBioComponent.kt index c2eeabe9..021c046a 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/components/header/UserBioComponent.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/components/header/UserBioComponent.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp private enum class UserBioState(val value: Int) { @@ -48,7 +49,8 @@ fun BindUserBio( .padding(16.dp), text = bioText, maxLines = target.value, - style = MaterialTheme.typography.titleSmall + style = MaterialTheme.typography.titleSmall, + overflow = TextOverflow.Ellipsis ) } } diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt index 626a8a9b..259ab83b 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserStore.kt @@ -2,7 +2,6 @@ package st.slex.csplashscreen.feature.user.ui.presenter import androidx.compose.runtime.Stable import androidx.paging.PagingData -import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.collection.ui.model.CollectionModel import st.slex.csplashscreen.core.navigation.AppArguments import st.slex.csplashscreen.core.network.model.ui.user.UserModel @@ -14,10 +13,19 @@ interface UserStore { @Stable data class State( val user: UserModel?, - val photos: (String) -> StateFlow>, - val likes: (String) -> StateFlow>, - val collections: (String) -> StateFlow> - ) : Store.State + val photos: PagingData, + val likes: PagingData, + val collections: PagingData + ) : Store.State { + companion object { + val INITIAL = State( + user = null, + photos = PagingData.empty(), + likes = PagingData.empty(), + collections = PagingData.empty() + ) + } + } @Stable sealed interface Event : Store.Event diff --git a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt index 2ba89cb5..a70a4ec1 100644 --- a/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt +++ b/feature/user/src/main/java/st/slex/csplashscreen/feature/user/ui/presenter/UserViewModel.kt @@ -3,7 +3,6 @@ package st.slex.csplashscreen.feature.user.ui.presenter import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import st.slex.csplashscreen.core.collection.ui.model.CollectionModel import st.slex.csplashscreen.core.collection.ui.model.toPresentation @@ -24,16 +23,11 @@ class UserViewModel @Inject constructor( private val interactor: UserInteractor, appDispatcher: AppDispatcher, router: UserRouter -) : BaseViewModel(router, appDispatcher) { - - override val initialState: State = State( - user = null, - likes = ::getLikes, - photos = ::getPhotos, - collections = ::getCollections - ) - - override val _state: MutableStateFlow = MutableStateFlow(initialState) +) : BaseViewModel( + router = router, + appDispatcher = appDispatcher, + initialState = State.INITIAL +) { override fun sendAction(action: Action) { when (action) { @@ -55,6 +49,27 @@ class UserViewModel @Inject constructor( currentState.copy(user = user) } } + + getPhotos(action.args.username) + .launch { photos -> + updateState { currentState -> + currentState.copy(photos = photos) + } + } + + getLikes(action.args.username) + .launch { likes -> + updateState { currentState -> + currentState.copy(likes = likes) + } + } + + getCollections(action.args.username) + .launch { collections -> + updateState { currentState -> + currentState.copy(collections = collections) + } + } } private fun getPhotos(