diff --git a/app/build.gradle b/app/build.gradle
index b9ae6e0..1950abb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -10,6 +10,13 @@ apply from: "${rootProject.projectDir}/gradle/compose-android-config.gradle"
android {
namespace 'com.moove'
+
+ defaultConfig {
+ buildConfigField "String", "FIREBASE_DYNAMIC_LINK_HOST", "\"$firebase_dynamic_link_host\""
+ manifestPlaceholders = [
+ firebaseDynamicLinkHost: "\"$firebase_dynamic_link_host\""
+ ]
+ }
}
dependencies {
@@ -26,6 +33,7 @@ dependencies {
implementation libs.androidx.fragment
implementation libs.bundles.androidx.navigation
implementation libs.bundles.androidx.lifecycle
+ implementation libs.bundles.androidx.compose
// endregion
// region Kotlin
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 19bcbe9..c1ef8b9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -30,6 +30,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/moove/app/MooveApp.kt b/app/src/main/java/com/moove/app/MooveApp.kt
index f151a58..01ca86c 100644
--- a/app/src/main/java/com/moove/app/MooveApp.kt
+++ b/app/src/main/java/com/moove/app/MooveApp.kt
@@ -2,10 +2,11 @@ package com.moove.app
import android.app.Application
import com.moove.app.di.coroutineModule
+import com.moove.app.di.deepLinkModule
import com.moove.app.di.exceptionsModule
import com.moove.app.di.mainModule
import com.moove.app.di.netModule
-import com.moove.app.di.ticketsModule
+import com.moove.tickets.di.ticketsModule
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
@@ -28,6 +29,7 @@ open class MooveApp : Application() {
exceptionsModule,
ticketsModule,
netModule,
+ deepLinkModule,
)
}
}
diff --git a/app/src/main/java/com/moove/app/di/DeepLinkModule.kt b/app/src/main/java/com/moove/app/di/DeepLinkModule.kt
new file mode 100644
index 0000000..160c45f
--- /dev/null
+++ b/app/src/main/java/com/moove/app/di/DeepLinkModule.kt
@@ -0,0 +1,42 @@
+package com.moove.app.di
+
+import com.google.firebase.Firebase
+import com.google.firebase.dynamiclinks.dynamicLinks
+import com.moove.BuildConfig
+import com.moove.app.feature.deeplink.data.DeeplinkDataRepository
+import com.moove.app.feature.deeplink.data.DynamicLinkDataRepository
+import com.moove.app.feature.deeplink.data.local.AppDeepLinkLocalDataSource
+import com.moove.app.feature.deeplink.data.remote.FirebaseDynamicLinkDataSource
+import com.moove.app.feature.deeplink.presentation.DeepLinkAppNavigator
+import com.moove.shared.feature.deeplink.domain.DeeplinkRepository
+import com.moove.shared.feature.deeplink.domain.DynamicLinkRepository
+import com.moove.shared.feature.deeplink.domain.GetDeeplinkUseCase
+import com.moove.shared.feature.deeplink.domain.GetDynamicLinkUseCase
+import com.moove.shared.feature.deeplink.presentation.DeepLinkNavigator
+import org.koin.dsl.module
+
+val deepLinkModule = module {
+
+ factory { DeeplinkDataRepository(get()) }
+ factory { DynamicLinkDataRepository(get()) }
+ factory {
+ DeepLinkAppNavigator(
+ ticketsNavigator = get(),
+ globalAppNavigator = get(),
+ )
+ }
+ factory {
+ FirebaseDynamicLinkDataSource(
+ host = BuildConfig.FIREBASE_DYNAMIC_LINK_HOST,
+// firebaseDynamicLinks = Firebase.dynamicLinks
+ )
+ }
+ factory { AppDeepLinkLocalDataSource() }
+ factory {
+ GetDeeplinkUseCase(
+ deeplinkRepository = get(),
+ getDynamicLinkUseCase = get(),
+ )
+ }
+ factory { GetDynamicLinkUseCase(get()) }
+}
diff --git a/app/src/main/java/com/moove/app/di/MainModule.kt b/app/src/main/java/com/moove/app/di/MainModule.kt
index 6e462e5..5c0fc65 100644
--- a/app/src/main/java/com/moove/app/di/MainModule.kt
+++ b/app/src/main/java/com/moove/app/di/MainModule.kt
@@ -1,20 +1,38 @@
package com.moove.app.di
-import android.app.Activity
-import com.moove.app.main.AppNavigator
+import com.moove.app.feature.home.HomeNavigator
+import com.moove.app.feature.home.HomeViewModel
import com.moove.app.main.MainActivityViewModel
+import com.moove.app.main.MainNavigator
+import com.moove.app.navigation.AppNavigator
+import com.moove.shared.navigation.GlobalAppNavigator
+import com.moove.shared.navigation.ScreenNavigator
+import com.moove.shared.navigation.TicketsNavigator
import org.koin.androidx.viewmodel.dsl.viewModelOf
+import org.koin.core.module.dsl.factoryOf
+import org.koin.dsl.binds
import org.koin.dsl.module
val mainModule = module {
- viewModelOf(::MainActivityViewModel)
-
factory {
AppNavigator(
navController = get(),
- coroutineScope = get(),
- context = get(),
+ )
+ } binds arrayOf(
+ ScreenNavigator::class,
+ GlobalAppNavigator::class,
+ TicketsNavigator::class,
+ )
+
+ factory {
+ HomeNavigator(
+ navController = get(),
+ screenNavigator = get(),
)
}
+ viewModelOf(::HomeViewModel)
+
+ viewModelOf(::MainActivityViewModel)
+ factoryOf(::MainNavigator)
}
diff --git a/app/src/main/java/com/moove/app/feature/deeplink/data/DeeplinkDataRepository.kt b/app/src/main/java/com/moove/app/feature/deeplink/data/DeeplinkDataRepository.kt
new file mode 100644
index 0000000..bcfe4c8
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/deeplink/data/DeeplinkDataRepository.kt
@@ -0,0 +1,14 @@
+package com.moove.app.feature.deeplink.data
+
+import com.moove.app.feature.deeplink.data.local.AppDeepLinkLocalDataSource
+import com.moove.shared.feature.deeplink.domain.DeepLink
+import com.moove.shared.feature.deeplink.domain.DeeplinkRepository
+
+class DeeplinkDataRepository(
+ private val localDataSource: AppDeepLinkLocalDataSource,
+) : DeeplinkRepository {
+
+ override suspend fun getDeepLink(uri: String): DeepLink {
+ return localDataSource.getDeepLinkData(uri)
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/deeplink/data/DynamicLinkDataRepository.kt b/app/src/main/java/com/moove/app/feature/deeplink/data/DynamicLinkDataRepository.kt
new file mode 100644
index 0000000..7dfcd0a
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/deeplink/data/DynamicLinkDataRepository.kt
@@ -0,0 +1,13 @@
+package com.moove.app.feature.deeplink.data
+
+import com.moove.app.feature.deeplink.data.remote.FirebaseDynamicLinkDataSource
+import com.moove.shared.feature.deeplink.domain.DynamicLinkRepository
+
+class DynamicLinkDataRepository(
+ private val dataSource: FirebaseDynamicLinkDataSource,
+) : DynamicLinkRepository {
+
+ override suspend fun parseLink(uri: String): String? {
+ return dataSource.parseLink(uri)
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/deeplink/data/local/AppDeepLinkLocalDataSource.kt b/app/src/main/java/com/moove/app/feature/deeplink/data/local/AppDeepLinkLocalDataSource.kt
new file mode 100644
index 0000000..2567502
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/deeplink/data/local/AppDeepLinkLocalDataSource.kt
@@ -0,0 +1,93 @@
+package com.moove.app.feature.deeplink.data.local
+
+import com.moove.app.feature.deeplink.domain.AppDeepLink
+import com.moove.core.kotlin.text.matchesPattern
+import com.moove.shared.feature.deeplink.domain.DeepLink
+import com.moove.tickets.domain.model.Fare
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.net.URI
+import java.net.URLDecoder
+import java.nio.charset.StandardCharsets
+
+class AppDeepLinkLocalDataSource(
+ private val backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO,
+) {
+
+ companion object {
+ private const val RYDER_ID = "ryderId"
+ private const val PRICE = "price"
+
+ const val HOME = "moove://app/home"
+ const val FARE_LIST = "moove://app/fare_list"
+ const val CONFIRM_CONFIRMATION = "/ticket/confirmation"
+ const val MOOVE_CONFIRM_CONFIRMATION = "moove://app/confirmation"
+ }
+
+ suspend fun getDeepLinkData(uri: String): DeepLink = withContext(backgroundDispatcher) {
+ when {
+ uri.matchesPattern(CONFIRM_CONFIRMATION) -> {
+ val innerUri = URI.create(uri)
+ val params = getQueryParams(innerUri)
+ AppDeepLink.Confirmation(
+ ryderId = params[RYDER_ID]!!,
+ fare = Fare(
+ description = "",
+ price = params[PRICE]?.toFloat()!!
+ ),
+ )
+ }
+
+ uri.matchesPattern(MOOVE_CONFIRM_CONFIRMATION) -> {
+ val innerUri = URI.create(uri)
+ val params = getQueryParams(innerUri)
+ AppDeepLink.Confirmation(
+ ryderId = params[RYDER_ID]!!,
+ fare = Fare(
+ description = "",
+ price = params[PRICE]?.toFloat()!!
+ ),
+ )
+ }
+
+ uri.isThat(FARE_LIST) -> {
+ val innerUri = URI.create(uri)
+ val params = getQueryParams(innerUri)
+ AppDeepLink.FareList(ryderId = params[RYDER_ID]!!)
+ }
+
+ uri.isThat(HOME) || uri.matchesPattern(HOME) -> AppDeepLink.Home
+ else -> AppDeepLink.Unknown
+ }
+ }
+
+ private fun String.isThat(type: String): Boolean {
+ /**
+ * Handle two cases
+ * app/profile/ and app/profile
+ */
+ return contains(type, ignoreCase = true)
+ }
+
+ private fun getQueryParams(url: URI): Map {
+ val query = url.query ?: return emptyMap()
+ return query
+ .split("&".toRegex())
+ .filter { it.isNotEmpty() }
+ .map(::mapQueryParameter)
+ .associateBy(keySelector = { it.first }, valueTransform = { it.second })
+ }
+
+ private fun mapQueryParameter(query: String): Pair {
+ val index = query.indexOf("=")
+ val key = if (index > 0) query.substring(0, index) else query
+ val value = if (index > 0 && query.length > index + 1) {
+ query.substring(index + 1)
+ } else null
+ return Pair(
+ URLDecoder.decode(key, StandardCharsets.UTF_8.name()),
+ URLDecoder.decode(value, StandardCharsets.UTF_8.name())
+ )
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/deeplink/data/remote/FirebaseDynamicLinkDataSource.kt b/app/src/main/java/com/moove/app/feature/deeplink/data/remote/FirebaseDynamicLinkDataSource.kt
new file mode 100644
index 0000000..8e5041a
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/deeplink/data/remote/FirebaseDynamicLinkDataSource.kt
@@ -0,0 +1,27 @@
+package com.moove.app.feature.deeplink.data.remote
+
+import android.net.Uri
+import com.google.firebase.dynamiclinks.FirebaseDynamicLinks
+import com.moove.core.kotlin.text.matchesPattern
+import com.moove.shared.feature.deeplink.domain.exceptions.DynamicLinkParseException
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.tasks.await
+import kotlinx.coroutines.withContext
+
+class FirebaseDynamicLinkDataSource(
+ private val host: String,
+// private val firebaseDynamicLinks: FirebaseDynamicLinks,
+ private val backgroundDispatcher: CoroutineDispatcher = Dispatchers.IO,
+) {
+
+ suspend fun parseLink(uri: String): String? = withContext(backgroundDispatcher) {
+ if (uri.matchesPattern(host).not()) return@withContext null
+ try {
+// firebaseDynamicLinks.getDynamicLink(Uri.parse(uri)).await().link?.toString()
+ "https://moove.page.link/45hj45j"
+ } catch (e: Exception) {
+ throw DynamicLinkParseException(cause = e)
+ }
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/deeplink/domain/AppDeepLink.kt b/app/src/main/java/com/moove/app/feature/deeplink/domain/AppDeepLink.kt
new file mode 100644
index 0000000..5bc693e
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/deeplink/domain/AppDeepLink.kt
@@ -0,0 +1,15 @@
+package com.moove.app.feature.deeplink.domain
+
+import com.moove.shared.feature.deeplink.domain.DeepLink
+import com.moove.tickets.domain.model.Fare
+
+sealed class AppDeepLink: DeepLink {
+ data object Unknown : AppDeepLink()
+ data object Home : AppDeepLink()
+ data class FareList(val ryderId: String) : AppDeepLink()
+
+ data class Confirmation(
+ val ryderId: String,
+ val fare: Fare,
+ ) : AppDeepLink()
+}
diff --git a/app/src/main/java/com/moove/app/feature/deeplink/presentation/DeepLinkAppNavigator.kt b/app/src/main/java/com/moove/app/feature/deeplink/presentation/DeepLinkAppNavigator.kt
new file mode 100644
index 0000000..294cfc4
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/deeplink/presentation/DeepLinkAppNavigator.kt
@@ -0,0 +1,28 @@
+package com.moove.app.feature.deeplink.presentation
+
+import com.moove.app.feature.deeplink.domain.AppDeepLink
+import com.moove.shared.feature.deeplink.domain.DeepLink
+import com.moove.shared.feature.deeplink.presentation.DeepLinkNavigator
+import com.moove.shared.navigation.GlobalAppNavigator
+import com.moove.shared.navigation.TicketsNavigator
+
+class DeepLinkAppNavigator(
+ private val globalAppNavigator: GlobalAppNavigator,
+ private val ticketsNavigator: TicketsNavigator,
+) : DeepLinkNavigator {
+ override fun navigateTo(link: DeepLink) {
+ when (link) {
+ is AppDeepLink.FareList -> ticketsNavigator.goFares(link.ryderId)
+ is AppDeepLink.Confirmation -> {
+ ticketsNavigator.goFares(link.ryderId)
+ ticketsNavigator.goToConfirmation(
+ ryderId = link.ryderId,
+ fareDescription = link.fare.description,
+ farePrice = link.fare.price
+ )
+ }
+
+ is AppDeepLink.Home, AppDeepLink.Unknown -> globalAppNavigator.goHome()
+ }
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/home/HomeFragment.kt b/app/src/main/java/com/moove/app/feature/home/HomeFragment.kt
new file mode 100644
index 0000000..98a063b
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/home/HomeFragment.kt
@@ -0,0 +1,28 @@
+package com.moove.app.feature.home
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import com.moove.shared.R
+import com.moove.shared.databinding.ComposeFragmentBinding
+import com.moove.shared.presentation.compose.platform.setAppComposeContent
+import com.moove.shared.presentation.fragment.delegate.viewBinding
+import org.koin.android.ext.android.inject
+import org.koin.core.parameter.parametersOf
+
+class HomeFragment : Fragment(R.layout.compose_fragment) {
+
+ private val viewBinding by viewBinding(ComposeFragmentBinding::bind)
+ private val navigator: HomeNavigator by inject {
+ parametersOf(findNavController(), lifecycleScope, requireContext())
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setAppComposeContent(viewBinding.compose) {
+ HomeRoute(navigator = navigator)
+ }
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/home/HomeNavigator.kt b/app/src/main/java/com/moove/app/feature/home/HomeNavigator.kt
new file mode 100644
index 0000000..ea8324c
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/home/HomeNavigator.kt
@@ -0,0 +1,19 @@
+package com.moove.app.feature.home
+
+import androidx.navigation.NavController
+import com.moove.shared.navigation.ScreenNavigator
+import com.moove.shared.navigation.navigateSafely
+
+class HomeNavigator(
+ private val navController: NavController,
+ private val screenNavigator: ScreenNavigator,
+) : ScreenNavigator {
+
+ fun goRyderList() {
+ navController.navigateSafely(HomeFragmentDirections.actionHomeFragmentToTicketsFlow())
+ }
+
+ override fun goBack() {
+ screenNavigator.goBack()
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/home/HomeRoute.kt b/app/src/main/java/com/moove/app/feature/home/HomeRoute.kt
new file mode 100644
index 0000000..272ce22
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/home/HomeRoute.kt
@@ -0,0 +1,39 @@
+package com.moove.app.feature.home
+
+import androidx.compose.material.ScaffoldState
+import androidx.compose.material.rememberScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import com.moove.shared.presentation.viewmodel.composableEffect
+import com.moove.shared.presentation.viewmodel.composableState
+import org.koin.androidx.compose.koinViewModel
+
+@Composable
+fun HomeRoute(
+ navigator: HomeNavigator,
+ viewModel: HomeViewModel = koinViewModel(),
+ scaffoldState: ScaffoldState = rememberScaffoldState(),
+) {
+ val state by viewModel.composableState()
+
+ HomeScreen(
+ uiState = state,
+ scaffoldState = scaffoldState,
+ onRyderClick = viewModel::onRyderClick,
+ )
+
+ viewModel.RenderEffect(navigator = navigator)
+}
+
+@Composable
+private fun HomeViewModel.RenderEffect(
+ navigator: HomeNavigator,
+) {
+ composableEffect { effect ->
+ when (effect) {
+ is HomeEffect.GoToRyderList -> {
+ navigator.goRyderList()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/moove/app/feature/home/HomeScreen.kt b/app/src/main/java/com/moove/app/feature/home/HomeScreen.kt
new file mode 100644
index 0000000..ff6f07d
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/home/HomeScreen.kt
@@ -0,0 +1,60 @@
+package com.moove.app.feature.home
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.material.ScaffoldState
+import androidx.compose.material.Text
+import androidx.compose.material.rememberScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.moove.design_system.compose.AppTheme
+import com.moove.design_system.compose.Button
+import com.moove.design_system.compose.Scaffold
+import com.moove.design_system.compose.Spacing
+
+@Composable
+fun HomeScreen(
+ uiState: HomeState,
+ scaffoldState: ScaffoldState = rememberScaffoldState(),
+ onRyderClick: () -> Unit,
+) {
+ Scaffold(
+ modifier = Modifier.statusBarsPadding(),
+ scaffoldState = scaffoldState,
+ content = {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+ Button(
+ modifier = Modifier
+ .clickable(onClick = { onRyderClick() })
+ .padding(horizontal = Spacing.S, vertical = Spacing.S),
+ onClick = onRyderClick
+ ) {
+ Text(
+ text = "Go to Ryders list",
+ style = AppTheme.typography.material.h1,
+ maxLines = 1,
+ )
+ }
+ }
+ }
+ )
+}
+
+@Preview(name = "Home Content", showBackground = true)
+@Composable
+fun PreviewHomeContent() {
+ AppTheme {
+ HomeScreen(
+ uiState = HomeState(),
+ onRyderClick = {}
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/moove/app/feature/home/HomeState.kt b/app/src/main/java/com/moove/app/feature/home/HomeState.kt
new file mode 100644
index 0000000..577ee45
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/home/HomeState.kt
@@ -0,0 +1,11 @@
+package com.moove.app.feature.home
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+class HomeState : Parcelable
+
+sealed class HomeEffect {
+ data object GoToRyderList : HomeEffect()
+}
diff --git a/app/src/main/java/com/moove/app/feature/home/HomeViewModel.kt b/app/src/main/java/com/moove/app/feature/home/HomeViewModel.kt
new file mode 100644
index 0000000..91275f6
--- /dev/null
+++ b/app/src/main/java/com/moove/app/feature/home/HomeViewModel.kt
@@ -0,0 +1,26 @@
+package com.moove.app.feature.home
+
+import androidx.lifecycle.ViewModel
+import com.moove.core.exception.ExceptionHandler
+import com.moove.core.exception.asCoroutineExceptionHandler
+import org.orbitmvi.orbit.Container
+import org.orbitmvi.orbit.ContainerHost
+import org.orbitmvi.orbit.syntax.simple.intent
+import org.orbitmvi.orbit.syntax.simple.postSideEffect
+import org.orbitmvi.orbit.viewmodel.container
+
+class HomeViewModel(
+ exceptionHandler: ExceptionHandler,
+) : ViewModel(), ContainerHost {
+
+ override val container: Container = container(
+ initialState = HomeState(),
+ buildSettings = {
+ this.exceptionHandler = exceptionHandler.asCoroutineExceptionHandler()
+ },
+ )
+
+ fun onRyderClick() = intent {
+ postSideEffect(HomeEffect.GoToRyderList)
+ }
+}
diff --git a/app/src/main/java/com/moove/app/main/AppNavigator.kt b/app/src/main/java/com/moove/app/main/AppNavigator.kt
deleted file mode 100644
index d3d8be3..0000000
--- a/app/src/main/java/com/moove/app/main/AppNavigator.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.moove.app.main
-
-import android.content.Context
-import androidx.navigation.NavController
-import kotlinx.coroutines.CoroutineScope
-
-class AppNavigator(
- private val navController: NavController,
- private val coroutineScope: CoroutineScope,
- private val context: Context,
-)
\ No newline at end of file
diff --git a/app/src/main/java/com/moove/app/main/MainActivity.kt b/app/src/main/java/com/moove/app/main/MainActivity.kt
index 24299c7..c98c79f 100644
--- a/app/src/main/java/com/moove/app/main/MainActivity.kt
+++ b/app/src/main/java/com/moove/app/main/MainActivity.kt
@@ -1,31 +1,78 @@
package com.moove.app.main
+import android.content.Intent
import android.os.Build
import android.os.Bundle
+import android.widget.Toast
+import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.navigation.fragment.NavHostFragment
+import com.moove.R
import com.moove.databinding.ActivityMainBinding
+import kotlinx.coroutines.launch
+import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
+import org.koin.core.parameter.parametersOf
class MainActivity : AppCompatActivity() {
- private lateinit var viewBinding: ActivityMainBinding
private val mainViewModel: MainActivityViewModel by viewModel()
+ private val navigator: MainNavigator by inject {
+ parametersOf(
+ (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment)
+ .navController,
+ lifecycleScope,
+ this
+ )
+ }
+ private lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
+
+ mainViewModel.handleIntent(intent)
+
+ observeSideEffect()
+ }
+
+ override fun onNewIntent(intent: Intent) {
+ super.onNewIntent(intent)
+ mainViewModel.handleIntent(intent)
+ }
+
+ private fun observeSideEffect() {
+ lifecycleScope.launch {
+ val sideEffectFlow = mainViewModel.container.sideEffectFlow
+ lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ sideEffectFlow.collect { effect ->
+ when (effect) {
+ is MainActivityEffect.NavigateDeepLink -> navigator.navigateDeepLink(effect.deepLink)
+ MainActivityEffect.ShowGenericError -> Toast.makeText(
+ this@MainActivity,
+ "Generic Error",
+ Toast.LENGTH_SHORT
+ )
+ }
+ }
+ }
+ }
}
- @Suppress("OVERRIDE_DEPRECATION", "DEPRECATION")
override fun onBackPressed() {
+ val backStackEntryCount = supportFragmentManager.primaryNavigationFragment
+ ?.childFragmentManager
+ ?.backStackEntryCount ?: 0
+
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q &&
isTaskRoot &&
- (supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.backStackEntryCount
- ?: 0) == 0 &&
- supportFragmentManager.backStackEntryCount == 0
+ backStackEntryCount == 0 && supportFragmentManager.backStackEntryCount == 0
) {
finishAfterTransition()
} else {
diff --git a/app/src/main/java/com/moove/app/main/MainActivityState.kt b/app/src/main/java/com/moove/app/main/MainActivityState.kt
index 4d49096..b94a814 100644
--- a/app/src/main/java/com/moove/app/main/MainActivityState.kt
+++ b/app/src/main/java/com/moove/app/main/MainActivityState.kt
@@ -1,9 +1,13 @@
package com.moove.app.main
import android.os.Parcelable
+import com.moove.shared.feature.deeplink.domain.DeepLink
import kotlinx.parcelize.Parcelize
@Parcelize
class MainActivityState : Parcelable
-sealed class MainActivityEffect
+sealed class MainActivityEffect {
+ data object ShowGenericError : MainActivityEffect()
+ data class NavigateDeepLink(val deepLink: DeepLink) : MainActivityEffect()
+}
diff --git a/app/src/main/java/com/moove/app/main/MainActivityViewModel.kt b/app/src/main/java/com/moove/app/main/MainActivityViewModel.kt
index 48cba3d..cd9d06a 100644
--- a/app/src/main/java/com/moove/app/main/MainActivityViewModel.kt
+++ b/app/src/main/java/com/moove/app/main/MainActivityViewModel.kt
@@ -1,24 +1,43 @@
package com.moove.app.main
-import androidx.lifecycle.SavedStateHandle
+import android.content.Intent
import androidx.lifecycle.ViewModel
import com.moove.core.exception.ExceptionHandler
import com.moove.core.exception.asCoroutineExceptionHandler
+import com.moove.shared.feature.deeplink.domain.GetDeeplinkUseCase
+import com.moove.shared.presentation.viewmodel.executeUseCase
import org.orbitmvi.orbit.Container
import org.orbitmvi.orbit.ContainerHost
+import org.orbitmvi.orbit.syntax.simple.intent
+import org.orbitmvi.orbit.syntax.simple.postSideEffect
import org.orbitmvi.orbit.viewmodel.container
class MainActivityViewModel(
exceptionHandler: ExceptionHandler,
- savedStateHandle: SavedStateHandle,
-) : ViewModel(),
- ContainerHost {
+ private val getDeeplinkUseCase: GetDeeplinkUseCase,
+) : ViewModel(), ContainerHost {
override val container: Container = container(
initialState = MainActivityState(),
- savedStateHandle = savedStateHandle,
buildSettings = {
this.exceptionHandler = exceptionHandler.asCoroutineExceptionHandler()
},
)
+
+ fun handleIntent(intent: Intent?) = intent {
+ if (intent == null) return@intent
+
+ val uri = getDeepLinkFromIntent(intent)
+ if (uri.isNullOrEmpty()) return@intent
+
+ executeUseCase { getDeeplinkUseCase(uri) }
+ .onSuccess { deeplink -> postSideEffect(MainActivityEffect.NavigateDeepLink(deeplink)) }
+ .onFailure { postSideEffect(MainActivityEffect.ShowGenericError) }
+ }
+
+ private fun getDeepLinkFromIntent(intent: Intent): String? {
+ return intent.takeIf {
+ Intent.ACTION_VIEW == it.action || Intent.ACTION_MAIN == it.action
+ }?.dataString
+ }
}
diff --git a/app/src/main/java/com/moove/app/main/MainNavigator.kt b/app/src/main/java/com/moove/app/main/MainNavigator.kt
new file mode 100644
index 0000000..455819a
--- /dev/null
+++ b/app/src/main/java/com/moove/app/main/MainNavigator.kt
@@ -0,0 +1,13 @@
+package com.moove.app.main
+
+import com.moove.shared.feature.deeplink.domain.DeepLink
+import com.moove.shared.feature.deeplink.presentation.DeepLinkNavigator
+
+class MainNavigator(
+ private val deepLinkNavigator: DeepLinkNavigator,
+) {
+
+ fun navigateDeepLink(link: DeepLink) {
+ deepLinkNavigator.navigateTo(link)
+ }
+}
diff --git a/app/src/main/java/com/moove/app/navigation/AppNavigator.kt b/app/src/main/java/com/moove/app/navigation/AppNavigator.kt
new file mode 100644
index 0000000..adecd21
--- /dev/null
+++ b/app/src/main/java/com/moove/app/navigation/AppNavigator.kt
@@ -0,0 +1,44 @@
+package com.moove.app.navigation
+
+import androidx.navigation.NavController
+import com.moove.MobileNavigationDirections
+import com.moove.app.feature.home.HomeFragmentDirections
+import com.moove.shared.navigation.GlobalAppNavigator
+import com.moove.shared.navigation.navigateSafely
+import com.moove.tickets.presentation.fare.FareListFragmentDirections
+import com.moove.tickets.presentation.fare.model.FareModel
+import com.moove.tickets.presentation.list.RyderListFragmentDirections
+
+class AppNavigator(
+ private val navController: NavController,
+) : GlobalAppNavigator {
+
+ override fun goFares(ryderId: String) {
+ navController.navigateSafely(HomeFragmentDirections.actionHomeFragmentToTicketsFlow())
+ navController.navigateSafely(
+ RyderListFragmentDirections.actionRydersFragmentToFareListFragment(ryderId = ryderId)
+ )
+ }
+
+ override fun goToConfirmation(ryderId: String, fareDescription: String, farePrice: Float) {
+ navController.navigateSafely(
+ FareListFragmentDirections.actionFareListFragmentToConfirmationFragment(
+ ryderId = ryderId,
+ fare = FareModel(
+ description = fareDescription,
+ price = farePrice
+ )
+ )
+ )
+ }
+
+ override fun goBack() {
+ navController.navigateUp()
+ }
+
+ override fun goHome() {
+ navController.navigateSafely(
+ MobileNavigationDirections.actionGlobalGoHome()
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/navigation/app_main_navigation.xml b/app/src/main/res/navigation/app_main_navigation.xml
index f46ecaf..f55f7b6 100644
--- a/app/src/main/res/navigation/app_main_navigation.xml
+++ b/app/src/main/res/navigation/app_main_navigation.xml
@@ -3,7 +3,21 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_navigation"
- app:startDestination="@id/tickets_flow">
+ app:startDestination="@id/homeFragment">
+
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index 21b9d61..7107c50 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,6 +6,10 @@ buildscript {
'targetSdkVersion' : 34
]
+ ext {
+ firebase_dynamic_link_host = 'moove.page.link'
+ }
+
repositories {
google()
mavenCentral()
diff --git a/core/src/main/java/com/moove/core/kotlin/text/StringExtensions.kt b/core/src/main/java/com/moove/core/kotlin/text/StringExtensions.kt
new file mode 100644
index 0000000..96c8891
--- /dev/null
+++ b/core/src/main/java/com/moove/core/kotlin/text/StringExtensions.kt
@@ -0,0 +1,10 @@
+package com.moove.core.kotlin.text
+
+import java.util.regex.Pattern
+
+fun String.matchesPattern(pattern: String): Boolean {
+ return Pattern
+ .compile("($pattern)")
+ .matcher(this)
+ .find()
+}
diff --git a/gradle/base-android-config.gradle b/gradle/base-android-config.gradle
index 1582d19..ae8f5a8 100644
--- a/gradle/base-android-config.gradle
+++ b/gradle/base-android-config.gradle
@@ -42,6 +42,7 @@ android {
}
buildFeatures {
+ buildConfig true
dataBinding false
viewBinding true
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 44fe4cb..63ab323 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,50 +1,51 @@
[versions]
# kotlin
gradle = "8.4.1"
-kotlin = "1.9.23"
-ksp = "1.9.22-1.0.17"
+kotlin = "1.9.24"
+ksp = "1.9.24-1.0.20"
coroutines = "1.8.1"
# androidx
-lifecycle = "2.8.0"
+lifecycle = "2.7.0"
navigation = "2.7.7"
# di
-koin = "3.5.3"
-koin_android = "3.5.3"
-koin_compose = "3.5.3"
+koin = "3.5.6"
+koin_android = "3.5.6"
+koin_compose = "3.5.6"
# presentation
-orbit = "7.1.0"
+orbit = "7.1.1"
# ui
compose = "1.6.7"
-composeCompiler = "1.5.11"
+composeCompiler = "1.5.14"
composeFoundation = "1.6.7"
composeMaterial = "1.6.7"
accompanist = "0.34.0"
paging = "3.3.0"
# io
-retrofit = "2.9.0"
+retrofit = "2.11.0"
moshi = "1.15.1"
-moshi_sealed = "0.25.1"
+moshi_sealed = "0.27.1"
room = "2.6.1"
# services
-firebase = "33.0.0"
+firebase = "33.1.0"
# checks
lint = "31.4.1"
core-ktx = "1.13.1"
junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
-appcompat = "1.6.1"
+appcompat = "1.7.0"
material = "1.12.0"
[libraries]
# core
androidx-core = "androidx.core:core-ktx:1.13.1"
-androidx-appcompat = "androidx.appcompat:appcompat:1.6.1"
+androidx-appcompat = "androidx.appcompat:appcompat:1.7.0"
androidx-fragment = "androidx.fragment:fragment-ktx:1.7.1"
androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment-ktx", version.ref = "navigation" }
androidx-navigation-ui = { module = "androidx.navigation:navigation-ui-ktx", version.ref = "navigation" }
androidx-lifecycle-common = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "lifecycle" }
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle" }
+androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
androidx-lifecycle-livedata = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycle" }
androidx-browser = "androidx.browser:browser:1.8.0"
@@ -125,12 +126,12 @@ firebase-perf = { module = "com.google.firebase:firebase-perf-ktx" }
firebase-messaging = { module = "com.google.firebase:firebase-messaging-ktx" }
firebase-inappmessaging = { module = "com.google.firebase:firebase-inappmessaging-display-ktx" }
firebase-installations = { module = "com.google.firebase:firebase-installations" }
-playservices-base = "com.google.android.gms:play-services-base:18.3.0"
-playservices-tasks = "com.google.android.gms:play-services-tasks:18.1.0"
-playservices-location = "com.google.android.gms:play-services-location:21.1.0"
+playservices-base = "com.google.android.gms:play-services-base:18.5.0"
+playservices-tasks = "com.google.android.gms:play-services-tasks:18.2.0"
+playservices-location = "com.google.android.gms:play-services-location:21.3.0"
playservices-maps = "com.google.android.gms:play-services-maps:18.2.0"
playservices-review = "com.google.android.play:review-ktx:2.0.1"
-playservices-ads-identifier = "com.google.android.gms:play-services-ads-identifier:18.0.1"
+playservices-ads-identifier = "com.google.android.gms:play-services-ads-identifier:18.1.0"
install-referrer = "com.android.installreferrer:installreferrer:2.2"
# tools
timber = "com.jakewharton.timber:timber:5.0.1"
@@ -162,12 +163,16 @@ androidx-navigation = ["androidx-navigation-fragment", "androidx-navigation-ui"]
androidx-lifecycle = [
"androidx-lifecycle-common", "androidx-lifecycle-runtime",
"androidx-lifecycle-viewmodel", "androidx-lifecycle-livedata",
+ "androidx-lifecycle-runtime-compose"
]
androidx-compose = [
- "androidx-compose-ui-core", "androidx-compose-ui-tooling",
+ "androidx-compose-ui-core",
+ "androidx-compose-ui-tooling",
"androidx-compose-foundation",
"androidx-compose-livedata",
- "androidx-compose-material-core", "androidx-compose-material-icons-core", "androidx-compose-material-icons-ext",
+ "androidx-compose-material-core",
+ "androidx-compose-material-icons-core",
+ "androidx-compose-material-icons-ext",
"androidx-compose-activity",
"androidx-compose-constraintlayout",
"androidx-compose-animation-graphics",
diff --git a/shared/build.gradle b/shared/build.gradle
index 6035be5..f2c7ac5 100644
--- a/shared/build.gradle
+++ b/shared/build.gradle
@@ -64,6 +64,9 @@ dependencies {
ksp libs.moshi.compiler
// endregion
+ api platform(libs.firebase.platform)
+ api libs.firebase.dynamic.links
+
// region Tests
api libs.javafaker
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DeepLink.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DeepLink.kt
new file mode 100644
index 0000000..f029249
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DeepLink.kt
@@ -0,0 +1,3 @@
+package com.moove.shared.feature.deeplink.domain
+
+interface DeepLink
\ No newline at end of file
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DeeplinkRepository.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DeeplinkRepository.kt
new file mode 100644
index 0000000..f18cf3d
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DeeplinkRepository.kt
@@ -0,0 +1,6 @@
+package com.moove.shared.feature.deeplink.domain
+
+interface DeeplinkRepository {
+
+ suspend fun getDeepLink(uri: String): DeepLink
+}
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DynamicLinkRepository.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DynamicLinkRepository.kt
new file mode 100644
index 0000000..b70e3c0
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/DynamicLinkRepository.kt
@@ -0,0 +1,6 @@
+package com.moove.shared.feature.deeplink.domain
+
+interface DynamicLinkRepository {
+
+ suspend fun parseLink(uri: String): String?
+}
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/domain/GetDeeplinkUseCase.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/GetDeeplinkUseCase.kt
new file mode 100644
index 0000000..e191444
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/GetDeeplinkUseCase.kt
@@ -0,0 +1,12 @@
+package com.moove.shared.feature.deeplink.domain
+
+class GetDeeplinkUseCase(
+ private val deeplinkRepository: DeeplinkRepository,
+ private val getDynamicLinkUseCase: GetDynamicLinkUseCase,
+) {
+ suspend operator fun invoke(uri: String): DeepLink {
+ val parsedUri = getDynamicLinkUseCase(uri) ?: uri
+ val deepLink = deeplinkRepository.getDeepLink(parsedUri)
+ return deepLink
+ }
+}
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/domain/GetDynamicLinkUseCase.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/GetDynamicLinkUseCase.kt
new file mode 100644
index 0000000..82cdc81
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/GetDynamicLinkUseCase.kt
@@ -0,0 +1,10 @@
+package com.moove.shared.feature.deeplink.domain
+
+class GetDynamicLinkUseCase(
+ private val dynamicLinkRepository: DynamicLinkRepository,
+) {
+
+ suspend operator fun invoke(uri: String): String? {
+ return dynamicLinkRepository.parseLink(uri)
+ }
+}
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/domain/exceptions/DynamicLinkParseException.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/exceptions/DynamicLinkParseException.kt
new file mode 100644
index 0000000..1e2b75a
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/domain/exceptions/DynamicLinkParseException.kt
@@ -0,0 +1,6 @@
+package com.moove.shared.feature.deeplink.domain.exceptions
+
+class DynamicLinkParseException(
+ message: String? = null,
+ cause: Throwable? = null,
+) : Exception(message, cause)
diff --git a/shared/src/main/java/com/moove/shared/feature/deeplink/presentation/DeepLinkNavigator.kt b/shared/src/main/java/com/moove/shared/feature/deeplink/presentation/DeepLinkNavigator.kt
new file mode 100644
index 0000000..6f4a4a6
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/feature/deeplink/presentation/DeepLinkNavigator.kt
@@ -0,0 +1,7 @@
+package com.moove.shared.feature.deeplink.presentation
+
+import com.moove.shared.feature.deeplink.domain.DeepLink
+
+interface DeepLinkNavigator {
+ fun navigateTo(link: DeepLink)
+}
diff --git a/shared/src/main/java/com/moove/shared/navigation/GlobalAppNavigator.kt b/shared/src/main/java/com/moove/shared/navigation/GlobalAppNavigator.kt
new file mode 100644
index 0000000..6e5e390
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/navigation/GlobalAppNavigator.kt
@@ -0,0 +1,6 @@
+package com.moove.shared.navigation
+
+interface GlobalAppNavigator : ScreenNavigator, TicketsNavigator {
+
+ fun goHome()
+}
diff --git a/shared/src/main/java/com/moove/shared/navigation/ScreenNavigator.kt b/shared/src/main/java/com/moove/shared/navigation/ScreenNavigator.kt
index 87f6d76..0bdf268 100644
--- a/shared/src/main/java/com/moove/shared/navigation/ScreenNavigator.kt
+++ b/shared/src/main/java/com/moove/shared/navigation/ScreenNavigator.kt
@@ -1,11 +1,5 @@
package com.moove.shared.navigation
-import androidx.navigation.NavController
-
-abstract class ScreenNavigator(
- private val navController: NavController
-) {
- open fun goBack() {
- navController.navigateUp()
- }
+interface ScreenNavigator {
+ fun goBack()
}
diff --git a/shared/src/main/java/com/moove/shared/navigation/TicketsNavigator.kt b/shared/src/main/java/com/moove/shared/navigation/TicketsNavigator.kt
new file mode 100644
index 0000000..cc0d424
--- /dev/null
+++ b/shared/src/main/java/com/moove/shared/navigation/TicketsNavigator.kt
@@ -0,0 +1,7 @@
+package com.moove.shared.navigation
+
+interface TicketsNavigator {
+
+ fun goFares(ryderId: String)
+ fun goToConfirmation(ryderId: String, fareDescription: String, farePrice: Float)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/moove/app/di/TicketsModule.kt b/tickets/src/main/java/com/moove/tickets/di/TicketsModule.kt
similarity index 93%
rename from app/src/main/java/com/moove/app/di/TicketsModule.kt
rename to tickets/src/main/java/com/moove/tickets/di/TicketsModule.kt
index fb98cb0..4d538e3 100644
--- a/app/src/main/java/com/moove/app/di/TicketsModule.kt
+++ b/tickets/src/main/java/com/moove/tickets/di/TicketsModule.kt
@@ -1,4 +1,4 @@
-package com.moove.app.di
+package com.moove.tickets.di
import com.moove.tickets.data.TicketsDataRepository
import com.moove.tickets.data.local.TicketsLocalDataSource
@@ -28,7 +28,7 @@ val ticketsModule = module {
single { TicketsDataRepository(get()) }
// endregion
- factory { RyderListNavigator(get()) }
+ factory { RyderListNavigator(get(), get()) }
viewModel {
RyderListViewModel(
exceptionHandler = get(),
@@ -36,7 +36,7 @@ val ticketsModule = module {
)
}
- factory { FareListNavigator(get()) }
+ factory { FareListNavigator(get(), get()) }
viewModel {
FareListViewModel(
exceptionHandler = get(),
diff --git a/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationNavigator.kt b/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationNavigator.kt
index 3e43d18..f945999 100644
--- a/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationNavigator.kt
+++ b/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationNavigator.kt
@@ -1,11 +1,12 @@
package com.moove.tickets.presentation.confirmation
-import androidx.navigation.NavController
import com.moove.shared.navigation.ScreenNavigator
-import com.moove.tickets.presentation.fare.model.FareModel
class ConfirmationNavigator(
- navController: NavController
-) : ScreenNavigator(navController) {
+ private val screenNavigator: ScreenNavigator,
+) : ScreenNavigator {
+ override fun goBack() {
+ screenNavigator.goBack()
+ }
}
diff --git a/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationRoute.kt b/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationRoute.kt
index 67bcdf1..3beb39c 100644
--- a/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationRoute.kt
+++ b/tickets/src/main/java/com/moove/tickets/presentation/confirmation/ConfirmationRoute.kt
@@ -12,6 +12,7 @@ import com.moove.shared.presentation.viewmodel.composableEffect
import com.moove.shared.presentation.viewmodel.composableState
import com.moove.tickets.presentation.fare.model.FareModel
import org.koin.androidx.compose.getViewModel
+import org.koin.androidx.compose.koinViewModel
import org.koin.core.parameter.parametersOf
@Composable
@@ -19,7 +20,7 @@ fun FareListRoute(
navigator: ConfirmationNavigator,
ryderId: String,
fare: FareModel,
- viewModel: ConfirmationViewModel = getViewModel { parametersOf(ryderId, fare) },
+ viewModel: ConfirmationViewModel = koinViewModel { parametersOf(ryderId, fare) },
scaffoldState: ScaffoldState = rememberScaffoldState(),
) {
val state by viewModel.composableState()
diff --git a/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListNavigator.kt b/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListNavigator.kt
index 0fb4fad..75071df 100644
--- a/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListNavigator.kt
+++ b/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListNavigator.kt
@@ -1,20 +1,19 @@
package com.moove.tickets.presentation.fare
-import androidx.navigation.NavController
import com.moove.shared.navigation.ScreenNavigator
-import com.moove.shared.navigation.navigateSafely
+import com.moove.shared.navigation.TicketsNavigator
import com.moove.tickets.presentation.fare.model.FareModel
class FareListNavigator(
- private val navController: NavController
-) : ScreenNavigator(navController) {
+ private val ticketsNavigator: TicketsNavigator,
+ private val screenNavigator: ScreenNavigator,
+) : ScreenNavigator {
fun goToConfirmation(ryderId: String, fare: FareModel) {
- navController.navigateSafely(
- FareListFragmentDirections.actionFareListFragmentToConfirmationFragment(
- ryderId = ryderId,
- fare = fare
- )
- )
+ ticketsNavigator.goToConfirmation(ryderId, fare.description, fare.price)
+ }
+
+ override fun goBack() {
+ screenNavigator.goBack()
}
}
diff --git a/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListRoute.kt b/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListRoute.kt
index 1662772..ae6abac 100644
--- a/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListRoute.kt
+++ b/tickets/src/main/java/com/moove/tickets/presentation/fare/FareListRoute.kt
@@ -9,13 +9,14 @@ import com.moove.shared.presentation.compose.component.showGenericError
import com.moove.shared.presentation.viewmodel.composableEffect
import com.moove.shared.presentation.viewmodel.composableState
import org.koin.androidx.compose.getViewModel
+import org.koin.androidx.compose.koinViewModel
import org.koin.core.parameter.parametersOf
@Composable
fun FareListRoute(
navigator: FareListNavigator,
ryderId: String,
- viewModel: FareListViewModel = getViewModel { parametersOf(ryderId) },
+ viewModel: FareListViewModel = koinViewModel { parametersOf(ryderId) },
scaffoldState: ScaffoldState = rememberScaffoldState(),
) {
val state by viewModel.composableState()
diff --git a/tickets/src/main/java/com/moove/tickets/presentation/list/RyderListNavigator.kt b/tickets/src/main/java/com/moove/tickets/presentation/list/RyderListNavigator.kt
index c8141d9..983dc6f 100644
--- a/tickets/src/main/java/com/moove/tickets/presentation/list/RyderListNavigator.kt
+++ b/tickets/src/main/java/com/moove/tickets/presentation/list/RyderListNavigator.kt
@@ -1,16 +1,18 @@
package com.moove.tickets.presentation.list
-import androidx.navigation.NavController
import com.moove.shared.navigation.ScreenNavigator
-import com.moove.shared.navigation.navigateSafely
+import com.moove.shared.navigation.TicketsNavigator
class RyderListNavigator(
- private val navController: NavController
-) : ScreenNavigator(navController) {
+ private val ticketsNavigator: TicketsNavigator,
+ private val screenNavigator: ScreenNavigator,
+) : ScreenNavigator {
fun goFares(id: String) {
- navController.navigateSafely(
- RyderListFragmentDirections.actionRydersFragmentToFareListFragment(ryderId = id)
- )
+ ticketsNavigator.goFares(id)
+ }
+
+ override fun goBack() {
+ screenNavigator.goBack()
}
}