Skip to content

Commit

Permalink
Share articles on social media feature.
Browse files Browse the repository at this point in the history
Now users can share articles on social media via link generated with the help of Firebase Dynamic Links.
  • Loading branch information
kasem-sm authored Apr 25, 2022
1 parent a31c5a2 commit 5ea8fe8
Show file tree
Hide file tree
Showing 41 changed files with 425 additions and 197 deletions.
3 changes: 2 additions & 1 deletion app/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/build
/build
.google-services.json
11 changes: 7 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ android {

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.gms.google-services'

def versionProperties = new Properties()
versionProperties.load(new FileInputStream(rootProject.file("version.properties")))

def _versionCode = "${versionProperties['VERSION_CODE']}".toInteger()
def _versionName =
"${versionProperties['MAJOR']}" +
".${versionProperties['VERSION_CODE']}" +
".${versionProperties['MINOR']}" +
".${versionProperties['PATCH']}"
".${versionProperties['VERSION_CODE']}" +
".${versionProperties['MINOR']}" +
".${versionProperties['PATCH']}"

android {
defaultConfig {
Expand Down Expand Up @@ -87,4 +88,6 @@ dependencies {
implementation(project(":ui-article-detail"))
implementation(project(":ui-subscribe-topic"))
implementation(project(":ui-bookmarks"))
}

implementation Firebase.dynamicLink
}
14 changes: 13 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@
android:scheme="https" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<!-- the host should contain your domain. The pattern should be same as it's mentioned without any special char -->

<data
android:host="slimektopensource.page.link"
android:scheme="https" />
</intent-filter>

</activity>

<provider
Expand Down Expand Up @@ -64,4 +76,4 @@

</application>

</manifest>
</manifest>
59 changes: 58 additions & 1 deletion app/src/main/java/kasem/sm/slime/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,25 @@
*/
package kasem.sm.slime

import android.content.Intent
import android.net.Uri
import android.os.Build.VERSION_CODES.S
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.RequiresApi
import coil.ImageLoader
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.google.accompanist.navigation.material.rememberBottomSheetNavigator
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kasem.sm.common_ui.util.Destination
import kasem.sm.slime.ui.navigation.SlimeNavigation
import timber.log.Timber

@OptIn(ExperimentalMaterialNavigationApi::class)
@AndroidEntryPoint
class MainActivity : ComponentActivity() {

Expand All @@ -24,7 +33,55 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SlimeNavigation(imageLoader = imageLoader)

val bottomSheetNavigator = rememberBottomSheetNavigator()
val navController = rememberAnimatedNavController(bottomSheetNavigator)

SlimeNavigation(
navController = navController,
imageLoader = imageLoader,
bottomSheetNavigator = bottomSheetNavigator
)

// Handle when app is opened via shareable link
FirebaseDynamicLinks.getInstance()
.getDynamicLink(intent)
.addOnSuccessListener(this) { pendingDynamicLinkData ->
var deepLink: Uri? = null

if (pendingDynamicLinkData != null) {
deepLink = pendingDynamicLinkData.link
}

deepLink?.let { link ->
val path =
link.toString().substring(link.toString().lastIndexOf("/") + 1)
when {
/**
* Only execute if the sharing link contains 'article' in it as our
* shareable link would look like https://slimektopensource.page.link/article/{articleId}
*/
link.toString().contains("article") -> {
val articleId = try {
path.toInt()
} catch (e: Exception) {
null
}

articleId?.let { id ->
navController.navigate(Destination.articleDetail(id))
// Clear the id from Intent
intent.apply {
data = null
Intent()
}
}
}
}
}
}.addOnFailureListener {
Timber.d(it.message)
}
}
}
}
12 changes: 6 additions & 6 deletions app/src/main/java/kasem/sm/slime/ui/navigation/NavExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ package kasem.sm.slime.ui.navigation
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import kasem.sm.common_ui.util.Routes
import kasem.sm.common_ui.util.Destination

@Composable
fun NavController.currentRouteAsState(): String? {
Expand All @@ -17,15 +17,15 @@ fun NavController.currentRouteAsState(): String? {
@Composable
fun NavController.isNotAuthRoute(): Boolean {
return when (currentRouteAsState()) {
Routes.HomeScreen.route -> true
Routes.ExploreScreen().route -> true
Routes.ProfileScreen.route -> true
Routes.BookmarkScreen.route -> true
Destination.HomeScreen.route -> true
Destination.ExploreScreen().route -> true
Destination.ProfileScreen.route -> true
Destination.BookmarkScreen.route -> true
else -> false
}
}

@Composable
fun NavController.isProfileScreenRoute(): Boolean {
return currentRouteAsState() == Routes.ProfileScreen.route
return currentRouteAsState() == Destination.ProfileScreen.route
}
6 changes: 3 additions & 3 deletions app/src/main/java/kasem/sm/slime/ui/navigation/NavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import com.google.accompanist.navigation.material.BottomSheetNavigator
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.google.accompanist.navigation.material.ModalBottomSheetLayout
import kasem.sm.common_ui.InitSlimeSystemUI
import kasem.sm.common_ui.util.Routes
import kasem.sm.common_ui.util.Routes.Main
import kasem.sm.common_ui.util.Destination
import kasem.sm.common_ui.util.Destination.Main

@OptIn(ExperimentalMaterialNavigationApi::class)
@Composable
Expand All @@ -31,7 +31,7 @@ fun NavHost(
AnimatedNavHost(
modifier = modifier,
navController = navController,
startDestination = Routes.HomeScreen.route,
startDestination = Destination.HomeScreen.route,
route = Main.route,
) {
attachLoginScreen(navController, snackbarHostState)
Expand Down
34 changes: 17 additions & 17 deletions app/src/main/java/kasem/sm/slime/ui/navigation/Screens.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import com.google.accompanist.navigation.animation.composable
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.google.accompanist.navigation.material.bottomSheet
import com.slime.ui_home.HomeScreen
import kasem.sm.common_ui.util.Routes
import kasem.sm.common_ui.util.Destination
import kasem.sm.ui_article_list.ListScreen
import kasem.sm.ui_auth.login.LoginScreen
import kasem.sm.ui_auth.register.RegisterScreen
Expand All @@ -33,7 +33,7 @@ fun NavGraphBuilder.attachRegistrationScreen(
navController: NavController,
snackbarHostState: SnackbarHostState,
) {
bottomSheet(Routes.RegisterScreen.route) {
bottomSheet(Destination.RegisterScreen.route) {
RegisterScreen(
viewModel = hiltViewModel(),
onRegistrationSuccess = {
Expand All @@ -48,7 +48,7 @@ internal fun NavGraphBuilder.attachLoginScreen(
navController: NavController,
snackbarHostState: SnackbarHostState,
) {
bottomSheet(route = Routes.LoginScreen.route) {
bottomSheet(route = Destination.LoginScreen.route) {
LoginScreen(
viewModel = hiltViewModel(),
onLoginSuccess = {
Expand All @@ -57,7 +57,7 @@ internal fun NavGraphBuilder.attachLoginScreen(
onSignUpClicked = {
// Remove the login sheet from stack
navController.popBackStack()
navController.navigate(Routes.RegisterScreen.route)
navController.navigate(Destination.RegisterScreen.route)
},
snackbarHostState = snackbarHostState
)
Expand All @@ -69,13 +69,13 @@ fun NavGraphBuilder.attachHomeScreen(
navController: NavController,
snackbarHostState: SnackbarHostState,
) {
composable(Routes.HomeScreen.route) {
composable(Destination.HomeScreen.route) {
HomeScreen(
viewModel = hiltViewModel(),
snackbarHostState = snackbarHostState,
imageLoader = imageLoader,
onArticleClick = { id ->
navController.navigate(Routes.articleDetailLink(id))
navController.navigate(Destination.articleDetail(id))
},
navigateTo = { route ->
navController.navigate(route)
Expand All @@ -93,7 +93,7 @@ fun NavGraphBuilder.attachExploreScreen(
snackbarHostState: SnackbarHostState,
) {
composable(
route = Routes.ExploreScreen().route,
route = Destination.ExploreScreen().route,
arguments = listOf(
navArgument("slime_topic") {
type = NavType.StringType
Expand All @@ -105,10 +105,10 @@ fun NavGraphBuilder.attachExploreScreen(
imageLoader = imageLoader,
snackbarHostState = snackbarHostState,
onArticleClick = { id ->
navController.navigate(Routes.articleDetailLink(id))
navController.navigate(Destination.articleDetail(id))
},
onTopicClick = { title, id ->
navController.navigate(Routes.ListScreen(title, id).route)
navController.navigate(Destination.ListScreen(title, id).route)
}
)
}
Expand All @@ -117,7 +117,7 @@ fun NavGraphBuilder.attachExploreScreen(
fun NavGraphBuilder.attachProfileScreen(
navController: NavController
) {
composable(Routes.ProfileScreen.route) {
composable(Destination.ProfileScreen.route) {
ProfileScreen(
viewModel = hiltViewModel(),
onLogOutSuccess = {
Expand All @@ -135,10 +135,10 @@ fun NavGraphBuilder.attachArticleDetailScreen(
snackbarHostState: SnackbarHostState,
) {
composable(
route = Routes.ArticleDetailScreen.route,
route = Destination.ArticleDetailScreen.route,
deepLinks = listOf(
navDeepLink {
uriPattern = Routes.articleDetailDeepLink + "{id}"
uriPattern = Destination.articleDetailDeepLink + "{id}"
}
)
) {
Expand All @@ -154,7 +154,7 @@ fun NavGraphBuilder.attachSelectTopicsScreen(
navController: NavController,
snackbarHostState: SnackbarHostState,
) {
composable(Routes.SubscribeTopicScreen.route) {
composable(Destination.SubscribeTopicScreen.route) {
SubscribeTopicScreen(
viewModel = hiltViewModel(),
snackbarHostState = snackbarHostState,
Expand All @@ -177,7 +177,7 @@ fun NavGraphBuilder.attachListScreen(
navController: NavController
) {
composable(
route = Routes.ListScreen().route,
route = Destination.ListScreen().route,
arguments = listOf(
navArgument("slime_topic") {
type = NavType.StringType
Expand All @@ -191,7 +191,7 @@ fun NavGraphBuilder.attachListScreen(
viewModel = hiltViewModel(),
imageLoader = imageLoader,
onArticleClick = { id ->
navController.navigate(Routes.articleDetailLink(id))
navController.navigate(Destination.articleDetail(id))
},
snackbarHostState = snackbarHostState,
navigateTo = {
Expand All @@ -205,12 +205,12 @@ fun NavGraphBuilder.attachBookmarksScreen(
imageLoader: ImageLoader,
navController: NavController
) {
composable(Routes.BookmarkScreen.route) {
composable(Destination.BookmarkScreen.route) {
BookmarksScreen(
viewModel = hiltViewModel(),
imageLoader = imageLoader
) { id ->
navController.navigate(Routes.articleDetailLink(id))
navController.navigate(Destination.articleDetail(id))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController
import coil.ImageLoader
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
import com.google.accompanist.navigation.material.BottomSheetNavigator
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.google.accompanist.navigation.material.rememberBottomSheetNavigator
import kasem.sm.common_ui.scaffold.SlimeBottomBar
import kasem.sm.common_ui.scaffold.SlimeScaffold
import kasem.sm.common_ui.util.BottomNavigationItems
Expand All @@ -23,10 +23,11 @@ import kasem.sm.slime.ui.theme.SlimeTheme
@OptIn(ExperimentalMaterialNavigationApi::class)
@RequiresApi(S)
@Composable
fun SlimeNavigation(imageLoader: ImageLoader) = SlimeTheme {
val bottomSheetNavigator = rememberBottomSheetNavigator()
val navController = rememberAnimatedNavController(bottomSheetNavigator)

fun SlimeNavigation(
imageLoader: ImageLoader,
navController: NavHostController,
bottomSheetNavigator: BottomSheetNavigator,
) = SlimeTheme {
val scaffoldState = rememberScaffoldState()

SlimeScaffold(
Expand Down
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ buildscript {
classpath Spotless.gradle
classpath Jetbrains.serializationGradle
classpath Extras.dependencyUpdates
classpath Firebase.gmsGoogleService
}
}

Expand Down Expand Up @@ -93,12 +94,12 @@ def provideUnitTestDeps(project) {

def provideUiTestDeps(project) {
project.dependencies {
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.2.0-alpha07"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.2.0-alpha08"
androidTestImplementation "androidx.test.ext:junit:1.1.4-alpha05"
androidTestImplementation "androidx.test.espresso:espresso-core:3.5.0-alpha05"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.1.1"
androidTestImplementation "com.google.truth:truth:1.1.3"
debugImplementation "androidx.compose.ui:ui-test-manifest:1.2.0-alpha07"
debugImplementation "androidx.compose.ui:ui-test-manifest:1.2.0-alpha08"
}
}

Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/Extras.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
object Extras {
private const val dependencyUpdatesVersion = "0.38.0"
const val dependencyUpdates = "com.github.ben-manes:gradle-versions-plugin:$dependencyUpdatesVersion"
}
}
7 changes: 7 additions & 0 deletions buildSrc/src/main/java/Firebase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
object Firebase {
private const val gmsVersion = "4.3.10"
const val gmsGoogleService = "com.google.gms:google-services:$gmsVersion"

private const val dynamicLinksVersion = "21.0.1"
const val dynamicLink = "com.google.firebase:firebase-dynamic-links-ktx:$dynamicLinksVersion"
}
Loading

0 comments on commit 5ea8fe8

Please sign in to comment.