-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from MkhytarMkhoian/feature/deeplink
Add deeplink support to the app
- Loading branch information
Showing
45 changed files
with
786 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<DeeplinkRepository> { DeeplinkDataRepository(get()) } | ||
factory<DynamicLinkRepository> { DynamicLinkDataRepository(get()) } | ||
factory<DeepLinkNavigator> { | ||
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()) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Activity>(), | ||
) | ||
} binds arrayOf( | ||
ScreenNavigator::class, | ||
GlobalAppNavigator::class, | ||
TicketsNavigator::class, | ||
) | ||
|
||
factory { | ||
HomeNavigator( | ||
navController = get(), | ||
screenNavigator = get(), | ||
) | ||
} | ||
viewModelOf(::HomeViewModel) | ||
|
||
viewModelOf(::MainActivityViewModel) | ||
factoryOf(::MainNavigator) | ||
} |
14 changes: 14 additions & 0 deletions
14
app/src/main/java/com/moove/app/feature/deeplink/data/DeeplinkDataRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
app/src/main/java/com/moove/app/feature/deeplink/data/DynamicLinkDataRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
93 changes: 93 additions & 0 deletions
93
app/src/main/java/com/moove/app/feature/deeplink/data/local/AppDeepLinkLocalDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<String, String> { | ||
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<String, String> { | ||
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()) | ||
) | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...src/main/java/com/moove/app/feature/deeplink/data/remote/FirebaseDynamicLinkDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
app/src/main/java/com/moove/app/feature/deeplink/domain/AppDeepLink.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() | ||
} |
28 changes: 28 additions & 0 deletions
28
app/src/main/java/com/moove/app/feature/deeplink/presentation/DeepLinkAppNavigator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() | ||
} | ||
} | ||
} |
Oops, something went wrong.