From 46b2f672d0708898fd5c06b523cfc0ce0fe19f9a Mon Sep 17 00:00:00 2001 From: kasem-sm Date: Tue, 24 May 2022 20:36:22 +0530 Subject: [PATCH 1/3] Fix subscription related minor issues. --- .../java/com/slime/ui_home/HomeContent.kt | 3 ++- .../main/java/com/slime/ui_home/HomeState.kt | 1 + .../src/main/java/com/slime/ui_home/HomeVM.kt | 27 ++++++++++++------- .../slime/ui_home/components/TopicsView.kt | 9 ++++--- .../components/TopicsListView.kt | 3 ++- version.properties | 4 +-- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/screen/ui-home/src/main/java/com/slime/ui_home/HomeContent.kt b/screen/ui-home/src/main/java/com/slime/ui_home/HomeContent.kt index 3e079cb8..7a1fee4b 100644 --- a/screen/ui-home/src/main/java/com/slime/ui_home/HomeContent.kt +++ b/screen/ui-home/src/main/java/com/slime/ui_home/HomeContent.kt @@ -71,8 +71,9 @@ internal fun HomeContent( topicsView( isLoading = state.isLoading, + isUserAuthenticated = state.isUserAuthenticated, topics = state.topics, - currentQuery = state.currentQuery, + currentTopic = state.currentQuery, onTopicChange = onTopicChange, navigateToSubscriptionScreen = navigateToSubscriptionScreen ) diff --git a/screen/ui-home/src/main/java/com/slime/ui_home/HomeState.kt b/screen/ui-home/src/main/java/com/slime/ui_home/HomeState.kt index 0e093574..a7aec7c8 100644 --- a/screen/ui-home/src/main/java/com/slime/ui_home/HomeState.kt +++ b/screen/ui-home/src/main/java/com/slime/ui_home/HomeState.kt @@ -12,6 +12,7 @@ import kasem.sm.topic.domain.model.Topic data class HomeState( val currentQuery: String = "", val isLoading: Boolean = true, + val isUserAuthenticated: Boolean = false, val topics: List = emptyList(), val dailyReadArticle: Article? = null, val articles: List
= emptyList(), diff --git a/screen/ui-home/src/main/java/com/slime/ui_home/HomeVM.kt b/screen/ui-home/src/main/java/com/slime/ui_home/HomeVM.kt index 78390773..0c6f3baf 100644 --- a/screen/ui-home/src/main/java/com/slime/ui_home/HomeVM.kt +++ b/screen/ui-home/src/main/java/com/slime/ui_home/HomeVM.kt @@ -30,7 +30,6 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import kotlinx.coroutines.plus @@ -55,16 +54,23 @@ class HomeVM @Inject constructor( private val loadingStatus = ObservableLoader() + private val isUserAuthenticated = SavedMutableState( + savedStateHandle, + USER_AUTH_KEY, + defValue = false + ) + private val _uiEvent = MutableSharedFlow() val uiEvent = _uiEvent.asSharedFlow() val state = combineFlows( searchQuery.flow, loadingStatus.flow, + isUserAuthenticated.flow, observeSubscribedTopics.flow, observeDailyReadArticle.flow, observeArticles.flow, - ) { currentQuery, isLoading, topics, + ) { currentQuery, isLoading, isUserAuthenticated, topics, dailyReadArticle, articles -> HomeState( currentQuery = currentQuery, @@ -72,6 +78,7 @@ class HomeVM @Inject constructor( topics = topics, dailyReadArticle = dailyReadArticle, articles = articles, + isUserAuthenticated = isUserAuthenticated ) }.stateIn(viewModelScope, HomeState.EMPTY) @@ -94,13 +101,14 @@ class HomeVM @Inject constructor( } private fun observeAuthState() { - viewModelScope.launch { - observeAuthState - .joinAndCollect(viewModelScope + dispatchers.main) - .filter { it == AuthState.LOGGED_IN } - .collectLatest { - refresh(subscriptionOnly = true) - } + viewModelScope.launch(dispatchers.main) { + observeAuthState.joinAndCollect( + coroutineScope = viewModelScope + dispatchers.main + ).collectLatest { + onQueryChange(DEFAULT_SEARCH_QUERY) + refresh(subscriptionOnly = true) + isUserAuthenticated.value = it == AuthState.LOGGED_IN + } } } @@ -152,5 +160,6 @@ class HomeVM @Inject constructor( companion object { const val QUERY_KEY = "slime_query" + const val USER_AUTH_KEY = "slime_home_is_user_authenticated" } } diff --git a/screen/ui-home/src/main/java/com/slime/ui_home/components/TopicsView.kt b/screen/ui-home/src/main/java/com/slime/ui_home/components/TopicsView.kt index a10c94e0..b4083d4d 100644 --- a/screen/ui-home/src/main/java/com/slime/ui_home/components/TopicsView.kt +++ b/screen/ui-home/src/main/java/com/slime/ui_home/components/TopicsView.kt @@ -32,12 +32,13 @@ import kasem.sm.topic.domain.model.Topic internal fun LazyListScope.topicsView( isLoading: Boolean, + isUserAuthenticated: Boolean, topics: List, - currentQuery: String, + currentTopic: String, onTopicChange: (String) -> Unit, navigateToSubscriptionScreen: () -> Unit ) { - if (!isLoading && topics.isEmpty()) { + if (!isLoading && topics.isEmpty() || !isUserAuthenticated) { item { SlimeCard( backgroundColor = MaterialTheme.colorScheme.primaryContainer, @@ -66,7 +67,7 @@ internal fun LazyListScope.topicsView( item { LazyRow { items(topics) { topic -> - val isSelected = currentQuery == topic.title + val isSelected = currentTopic == topic.title val backgroundColor = animateColorAsState( targetValue = when (isSelected) { @@ -90,7 +91,7 @@ internal fun LazyListScope.topicsView( modifier = Modifier .padding(10.dp) .toggleWithRipple( - value = currentQuery == topic.title, + value = currentTopic == topic.title, ) { value -> when (value) { true -> onTopicChange(topic.title) diff --git a/screen/ui-subscribe-topic/src/main/java/kasem/sm/ui_subscribe_topic/components/TopicsListView.kt b/screen/ui-subscribe-topic/src/main/java/kasem/sm/ui_subscribe_topic/components/TopicsListView.kt index 5f1b47d8..950b4e3a 100644 --- a/screen/ui-subscribe-topic/src/main/java/kasem/sm/ui_subscribe_topic/components/TopicsListView.kt +++ b/screen/ui-subscribe-topic/src/main/java/kasem/sm/ui_subscribe_topic/components/TopicsListView.kt @@ -7,6 +7,7 @@ package kasem.sm.ui_subscribe_topic.components import androidx.compose.runtime.Composable import kasem.sm.common_ui.SlimeFlowRow import kasem.sm.ui_subscribe_topic.SubscribeTopicState +import kasem.sm.ui_subscribe_topic.SubscribeTopicState.Companion.loadingStatus @Composable internal fun TopicsListView( @@ -17,7 +18,7 @@ internal fun TopicsListView( state.topics.forEachIndexed { itemsIndex, topic -> SelectableTopicCard( topic = topic, - enabled = !state.isLoading, + enabled = !state.loadingStatus, onClick = { updateList(itemsIndex) } diff --git a/version.properties b/version.properties index 451ab83a..2bb03c40 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Tue May 24 20:07:55 IST 2022 +#Tue May 24 20:35:34 IST 2022 MAJOR=0 MINOR=0 VERSION_CODE=31 -PATCH=4183 +PATCH=4188 From 1b439442629272bfc8b0680adad64cb74a662c63 Mon Sep 17 00:00:00 2001 From: kasem-sm Date: Tue, 24 May 2022 22:01:28 +0530 Subject: [PATCH 2/3] Added `NavigationRail` for large screen devices or when device is rotated, instead of `BottomNav` --- app/build.gradle | 1 + .../main/java/kasem/sm/slime/MainActivity.kt | 6 +- .../sm/slime/ui/navigation/SlimeNavigation.kt | 89 ++++++++++++------- common-ui/build.gradle | 2 + .../sm/common_ui/scaffold/SlimeBottomBar.kt | 39 ++++++++ .../sm/common_ui/scaffold/SlimeScaffold.kt | 16 ++-- version.properties | 4 +- 7 files changed, 119 insertions(+), 38 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5502224b..ce799b16 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -90,6 +90,7 @@ dependencies { implementation Firebase.dynamicLink implementation(project(":features:article:dynamic-links-handler")) + implementation "androidx.compose.material3:material3-window-size-class:1.0.0-alpha12" } if (file("google-services.json").exists()) { diff --git a/app/src/main/java/kasem/sm/slime/MainActivity.kt b/app/src/main/java/kasem/sm/slime/MainActivity.kt index 64dbdcfd..fe15f97d 100644 --- a/app/src/main/java/kasem/sm/slime/MainActivity.kt +++ b/app/src/main/java/kasem/sm/slime/MainActivity.kt @@ -9,6 +9,8 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.annotation.RequiresApi +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import coil.ImageLoader import com.google.accompanist.navigation.animation.rememberAnimatedNavController import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi @@ -27,6 +29,7 @@ class MainActivity : ComponentActivity() { @Inject lateinit var imageLoader: ImageLoader + @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) @RequiresApi(S) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -37,7 +40,8 @@ class MainActivity : ComponentActivity() { SlimeNavigation( navController = navController, imageLoader = imageLoader, - bottomSheetNavigator = bottomSheetNavigator + bottomSheetNavigator = bottomSheetNavigator, + windowSizeClass = calculateWindowSizeClass(this) ) handleDynamicLink( diff --git a/app/src/main/java/kasem/sm/slime/ui/navigation/SlimeNavigation.kt b/app/src/main/java/kasem/sm/slime/ui/navigation/SlimeNavigation.kt index 68121d47..37c9b147 100644 --- a/app/src/main/java/kasem/sm/slime/ui/navigation/SlimeNavigation.kt +++ b/app/src/main/java/kasem/sm/slime/ui/navigation/SlimeNavigation.kt @@ -6,17 +6,23 @@ package kasem.sm.slime.ui.navigation import android.os.Build.VERSION_CODES.S import androidx.annotation.RequiresApi +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.rememberScaffoldState +import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.navigation.NavController import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import coil.ImageLoader import com.google.accompanist.navigation.material.BottomSheetNavigator import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi import kasem.sm.common_ui.scaffold.SlimeBottomBar +import kasem.sm.common_ui.scaffold.SlimeNavigationRail import kasem.sm.common_ui.scaffold.SlimeScaffold +import kasem.sm.common_ui.scaffold.isCompactWindow import kasem.sm.common_ui.theme.SlimeTheme import kasem.sm.common_ui.util.BottomNavigationItems @@ -27,38 +33,61 @@ fun SlimeNavigation( imageLoader: ImageLoader, navController: NavHostController, bottomSheetNavigator: BottomSheetNavigator, -) = SlimeTheme { - val scaffoldState = rememberScaffoldState() + windowSizeClass: WindowSizeClass, +) { + SlimeTheme { + val scaffoldState = rememberScaffoldState() - SlimeScaffold( - state = scaffoldState, - bottomBarVisibility = navController.isNotAuthRoute(), - fabVisibility = navController.isProfileScreenRoute(), - bottomBar = { - SlimeBottomBar( - currentRoute = navController.currentRouteAsState(), - items = BottomNavigationItems.toList, - navigateTo = { route -> - if (navController.currentDestination?.route != route) { - navController.navigate(route) { - popUpTo(navController.graph.findStartDestination().id) { - saveState = true - } - launchSingleTop = true - restoreState = true - } - } + SlimeScaffold( + state = scaffoldState, + bottomBarVisibility = navController.isNotAuthRoute(), + fabVisibility = navController.isProfileScreenRoute(), + windowSizeClass = windowSizeClass, + bottomBar = { + SlimeBottomBar( + currentRoute = navController.currentRouteAsState(), + items = BottomNavigationItems.toList, + navigateTo = navController::navigateTo + ) + }, + ) { padding -> + /** + * If the device is rotated (horizontally), we need to display + * the rail first in the row then the content + */ + Row( + Modifier + .fillMaxSize() + ) { + if (!windowSizeClass.isCompactWindow) { + SlimeNavigationRail( + currentRoute = navController.currentRouteAsState(), + items = BottomNavigationItems.toList, + navigateTo = navController::navigateTo + ) } - ) + + NavHost( + navController = navController, + bottomSheetNavigator = bottomSheetNavigator, + imageLoader = imageLoader, + snackbarHostState = scaffoldState.snackbarHostState, + modifier = Modifier + .padding(padding) + ) + } + } + } +} + +fun NavController.navigateTo(route: String) { + if (currentDestination?.route != route) { + navigate(route) { + popUpTo(graph.findStartDestination().id) { + saveState = true + } + launchSingleTop = true + restoreState = true } - ) { padding -> - NavHost( - navController = navController, - bottomSheetNavigator = bottomSheetNavigator, - imageLoader = imageLoader, - snackbarHostState = scaffoldState.snackbarHostState, - modifier = Modifier - .padding(padding) - ) } } diff --git a/common-ui/build.gradle b/common-ui/build.gradle index 00613a3a..8e2c6df3 100644 --- a/common-ui/build.gradle +++ b/common-ui/build.gradle @@ -22,4 +22,6 @@ dependencies { implementation(Accompanist.flowLayout) implementation Accompanist.sysUiController implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.21" + + implementation "androidx.compose.material3:material3-window-size-class:1.0.0-alpha12" } diff --git a/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt b/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt index 17690632..adc77093 100644 --- a/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt +++ b/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt @@ -9,7 +9,11 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.NavigationRail +import androidx.compose.material3.NavigationRailItem import androidx.compose.material3.Text +import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource @@ -48,3 +52,38 @@ fun SlimeBottomBar( } } } + + +@Composable +fun SlimeNavigationRail( + currentRoute: String?, + navigateTo: (String) -> Unit, + items: List, +) { + NavigationRail { + items.forEach { item -> + NavigationRailItem( + icon = { + Icon( + painter = painterResource(id = item.icon), + modifier = Modifier.size(22.dp), + contentDescription = item.title, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + }, + label = { + Text( + text = item.title, + fontFamily = LocalSlimeFont.current.secondaryMedium + ) + }, + selected = currentRoute == item.route, + onClick = { + navigateTo(item.route) + } + ) + } + } +} + +val WindowSizeClass.isCompactWindow get() = widthSizeClass == WindowWidthSizeClass.Compact diff --git a/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeScaffold.kt b/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeScaffold.kt index f4b5d27a..ea30d7dd 100644 --- a/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeScaffold.kt +++ b/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeScaffold.kt @@ -11,6 +11,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon +import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -19,6 +20,7 @@ fun SlimeScaffold( state: ScaffoldState, bottomBarVisibility: Boolean, fabVisibility: Boolean, + windowSizeClass: WindowSizeClass, bottomBar: @Composable () -> Unit, content: @Composable (PaddingValues) -> Unit, ) { @@ -28,20 +30,24 @@ fun SlimeScaffold( content = content, bottomBar = { if (bottomBarVisibility) { - bottomBar() + if (windowSizeClass.isCompactWindow) { + bottomBar() + } } }, floatingActionButton = { if (fabVisibility) { - FloatingActionButton(onClick = { - // - }) { + FloatingActionButton( + onClick = { + // + } + ) { Icon( imageVector = Icons.Default.Add, contentDescription = Icons.Default.Add.name ) } } - } + }, ) } diff --git a/version.properties b/version.properties index 2bb03c40..af2c9866 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Tue May 24 20:35:34 IST 2022 +#Tue May 24 21:58:36 IST 2022 MAJOR=0 MINOR=0 VERSION_CODE=31 -PATCH=4188 +PATCH=4197 From 4da37a141baae8a90fca310b8fcd9664f4766a18 Mon Sep 17 00:00:00 2001 From: kasem-sm Date: Tue, 24 May 2022 22:04:57 +0530 Subject: [PATCH 3/3] Fix Lint --- .../main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt | 1 - version.properties | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt b/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt index adc77093..8f32a23a 100644 --- a/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt +++ b/common-ui/src/main/java/kasem/sm/common_ui/scaffold/SlimeBottomBar.kt @@ -53,7 +53,6 @@ fun SlimeBottomBar( } } - @Composable fun SlimeNavigationRail( currentRoute: String?, diff --git a/version.properties b/version.properties index 78bb4e9a..5b9005da 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Tue May 24 21:58:36 IST 2022 +#Tue May 24 22:03:57 IST 2022 MAJOR=0 MINOR=0 VERSION_CODE=31 -PATCH=4197 \ No newline at end of file +PATCH=4198