Skip to content

Commit

Permalink
Merge pull request #42 from stslex/dev
Browse files Browse the repository at this point in the history
refactor navigation
  • Loading branch information
stslex authored Oct 28, 2024
2 parents 6362b58 + 2bf2611 commit b420aaa
Show file tree
Hide file tree
Showing 113 changed files with 1,278 additions and 1,242 deletions.
1 change: 1 addition & 0 deletions commonApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ kotlin {
implementation(project(":core:network"))
implementation(project(":core:database"))
implementation(project(":core:ui"))
implementation(project(":core:navigation"))

implementation(project(":feature:film_feed"))
implementation(project(":feature:film"))
Expand Down
50 changes: 4 additions & 46 deletions commonApp/src/commonMain/kotlin/com/stslex/wizard/App.kt
Original file line number Diff line number Diff line change
@@ -1,59 +1,17 @@
package com.stslex.wizard

import androidx.compose.runtime.Composable
import com.stslex.wizard.core.core.coreModule
import com.stslex.wizard.core.database.di.coreDatabaseModule
import com.stslex.wizard.core.database.di.userSettingsModule
import com.stslex.wizard.core.network.di.coreNetworkModule
import com.stslex.wizard.core.ui.di.coreUiModule
import com.stslex.wizard.config.KoinApp
import com.stslex.wizard.core.ui.theme.AppTheme
import com.stslex.wizard.di.appModule
import com.stslex.wizard.feature.auth.di.featureAuthModule
import com.stslex.wizard.feature.favourite.di.featureFavouriteModule
import com.stslex.wizard.feature.film.di.featureFilmModule
import com.stslex.wizard.feature.film_feed.di.featureFeedModule
import com.stslex.wizard.feature.follower.di.featureFollowerModule
import com.stslex.wizard.feature.match.di.featureMatchModule
import com.stslex.wizard.feature.match_feed.di.featureMatchFeedModule
import com.stslex.wizard.feature.profile.di.featureProfileModule
import com.stslex.wizard.feature.settings.di.featureSettingsModule
import org.koin.compose.KoinApplication
import org.koin.core.KoinApplication

@Composable
fun App(
additionalSetup: KoinApplication.() -> Unit = {},
) {
KoinApplication(
application = {
setupCommonModules()
additionalSetup()
}
) {
KoinApp(additionalSetup) { controller ->
AppTheme {
InitialApp()
InitialApp(controller)
}
}
}

private fun KoinApplication.setupCommonModules() {
modules(
listOf(
appModule,
coreModule,
coreUiModule,
coreNetworkModule,
userSettingsModule,
coreDatabaseModule,
featureFeedModule,
featureFilmModule,
featureProfileModule,
featureMatchFeedModule,
featureAuthModule,
featureFollowerModule,
featureFavouriteModule,
featureSettingsModule,
featureMatchModule
)
)
}
}
60 changes: 43 additions & 17 deletions commonApp/src/commonMain/kotlin/com/stslex/wizard/InitialApp.kt
Original file line number Diff line number Diff line change
@@ -1,61 +1,87 @@
package com.stslex.wizard

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.transitions.SlideTransition
import androidx.navigation.NavHostController
import com.stslex.wizard.bottom_bar.BottomAppBarResource
import com.stslex.wizard.bottom_bar.BottomAppBarResource.Companion.getByRoute
import com.stslex.wizard.bottom_bar.MainBottomAppBar
import com.stslex.wizard.core.core.Logger
import com.stslex.wizard.core.navigation.Screen
import com.stslex.wizard.core.network.utils.token.AuthController
import com.stslex.wizard.core.ui.navigation.AppNavigator
import com.stslex.wizard.core.ui.navigation.AppScreen
import com.stslex.wizard.feature.auth.ui.AuthScreen
import com.stslex.wizard.main_screen.MainScreen
import com.stslex.wizard.host.AppNavigationHost
import org.koin.compose.getKoin

@Composable
fun InitialApp(
navHostController: NavHostController,
modifier: Modifier = Modifier
) {
val koin = getKoin()
val userStore = remember {
koin.get<AuthController>()
}
val navigator = remember {
koin.get<AppNavigator>()
var currentDestination by remember {
mutableStateOf<Screen?>(null)
}

navHostController.addOnDestinationChangedListener { _, destination, _ ->
Logger.d("current route: ${destination.route}")
currentDestination = destination.route?.let(::getByRoute)
Logger.d("currentDestination: $currentDestination")
}

LaunchedEffect(Unit) {
userStore.isAuthFlow.collect { isAuth ->
val currentScreen = navigator.currentScreen
val currentScreen = navHostController.currentDestination
if (
isAuth.not() &&
currentScreen != null &&
currentScreen != AppScreen.Auth
currentScreen.route != Screen.Auth.serializer().toString()
) {
navigator.navigate(AppScreen.Auth)
navHostController.navigate(Screen.Auth)
}
}
}

Scaffold(
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.background(MaterialTheme.colorScheme.background),
bottomBar = {
AnimatedVisibility(
visible = BottomAppBarResource.isAppbar(currentDestination),
enter = slideInVertically(tween(300)) { it },
exit = slideOutVertically(tween(300)) { it }
) {
MainBottomAppBar(
onBottomAppBarClick = { navHostController.navigate(it) },
currentDestination = currentDestination
)
}
}
) { _ ->
Box(
modifier = Modifier.fillMaxSize()
) {
Navigator(
screen = if (userStore.isAuth) MainScreen else AuthScreen
) {
SlideTransition(it)
}
AppNavigationHost(
navHostController = navHostController,
startScreen = if (userStore.isAuth) Screen.Auth else Screen.FilmFeed
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.stslex.wizard.bottom_bar;

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.automirrored.outlined.List
import androidx.compose.material.icons.filled.AccountBox
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.outlined.AccountBox
import androidx.compose.material.icons.outlined.PlayArrow
import androidx.compose.ui.graphics.vector.ImageVector
import com.stslex.wizard.core.navigation.Screen
import kotlin.reflect.KClass

enum class BottomAppBarResource(
val unselectedIcon: ImageVector,
val selectedIcon: ImageVector,
val title: String,
val screen: Screen
) {
FILM_FEED(
unselectedIcon = Icons.AutoMirrored.Outlined.List,
selectedIcon = Icons.AutoMirrored.Filled.List,
title = "films",
screen = Screen.FilmFeed
),
MATCHES(
unselectedIcon = Icons.Outlined.PlayArrow,
selectedIcon = Icons.Default.PlayArrow,
title = "matches",
screen = Screen.Match(Screen.Match.Type.SELF)
),
PROFILE(
unselectedIcon = Icons.Outlined.AccountBox,
selectedIcon = Icons.Default.AccountBox,
title = "profile",
screen = Screen.Profile(Screen.Profile.Type.SELF)
);

fun getIcon(isSelected: Boolean) = if (isSelected) selectedIcon else unselectedIcon

companion object {

fun isAppbar(screen: Any?): Boolean = entries.any { it.screen == screen }

fun getByRoute(route: String): Screen? = when {
Screen.FilmFeed::class.checkScreen(route) -> FILM_FEED
Screen.Match::class.checkScreen(route) -> MATCHES
Screen.Profile::class.checkScreen(route) -> PROFILE
else -> null
}?.screen

private fun <T : Screen> KClass<T>.checkScreen(route: String): Boolean =
route.contains(simpleName.orEmpty())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.stslex.wizard.bottom_bar

import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.stslex.wizard.core.navigation.Screen

@Composable
fun MainBottomAppBar(
onBottomAppBarClick: (Screen) -> Unit,
currentDestination: Screen?
) {
NavigationBar(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
) {
BottomAppBarResource
.entries
.forEach { item ->
val isSelected = currentDestination == item.screen
BottomAppBarItem(
item = item,
isSelected = isSelected,
onBottomAppBarClick = remember(item) {
onBottomAppBarClick
}
)
}
}
}

@Composable
private fun RowScope.BottomAppBarItem(
item: BottomAppBarResource,
isSelected: Boolean,
onBottomAppBarClick: (Screen) -> Unit
) {
NavigationBarItem(
selected = isSelected,
onClick = {
onBottomAppBarClick(item.screen)
},
icon = {
Icon(
imageVector = item.getIcon(isSelected),
contentDescription = null
)
},
label = {
Text(text = item.title)
},
alwaysShowLabel = false
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.stslex.wizard.config

import androidx.compose.runtime.Composable
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.stslex.wizard.di.appModules
import org.koin.compose.KoinApplication
import org.koin.core.KoinApplication

@Composable
fun KoinApp(
additionalSetup: KoinApplication.() -> Unit = {},
content: @Composable (navHostController: NavHostController) -> Unit
) {
val navHostController = rememberNavController()
KoinApplication(
application = {
modules(appModules(navHostController))
additionalSetup()
},
content = {
content(navHostController)
}
)
}
40 changes: 32 additions & 8 deletions commonApp/src/commonMain/kotlin/com/stslex/wizard/di/appModule.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
package com.stslex.wizard.di

import com.stslex.wizard.core.ui.navigation.AppNavigator
import com.stslex.wizard.navigator.AppNavigatorImpl
import org.koin.dsl.module
import androidx.navigation.NavHostController
import com.stslex.wizard.core.core.ModuleCore
import com.stslex.wizard.core.core.modules
import com.stslex.wizard.core.database.di.ModuleCoreDatabase
import com.stslex.wizard.core.navigation.di.ModuleCoreNavigation
import com.stslex.wizard.core.network.di.ModuleCoreNetwork
import com.stslex.wizard.core.ui.di.ModuleCoreUi
import com.stslex.wizard.feature.auth.di.ModuleFeatureAuth
import com.stslex.wizard.feature.favourite.di.ModuleFeatureFavourite
import com.stslex.wizard.feature.film.di.ModuleFeatureFilm
import com.stslex.wizard.feature.film_feed.di.ModuleFeatureFeed
import com.stslex.wizard.feature.follower.di.ModuleFeatureFollower
import com.stslex.wizard.feature.match.di.ModuleFeatureMatch
import com.stslex.wizard.feature.match_feed.di.ModuleFeatureMatchFeed
import com.stslex.wizard.feature.profile.di.ModuleFeatureProfile
import com.stslex.wizard.feature.settings.di.ModuleFeatureSettings

val appModule = module {
single<AppNavigator> {
AppNavigatorImpl()
}
}
fun appModules(navHostController: NavHostController) = listOf(
ModuleCore(),
ModuleCoreUi(),
ModuleCoreNetwork(),
ModuleCoreNavigation(navHostController),
ModuleCoreDatabase(),
ModuleFeatureFeed(),
ModuleFeatureFilm(),
ModuleFeatureProfile(),
ModuleFeatureMatchFeed(),
ModuleFeatureAuth(),
ModuleFeatureFollower(),
ModuleFeatureFavourite(),
ModuleFeatureSettings(),
ModuleFeatureMatch(),
).modules
Loading

0 comments on commit b420aaa

Please sign in to comment.