Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,18 @@ android {
namespace = "com.doyoonkim.knutice"
compileSdk = 35

val properties = Properties().apply {
load(FileInputStream("${rootDir}/local.properties"))
}
val apiMigrated = properties["api_migrated"] ?: ""

defaultConfig {
applicationId = "com.doyoonkim.knutice"
minSdk = 31
targetSdk = 35
versionCode = 26
versionName = "1.5.0"
versionCode = 27
versionName = "1.5.1"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}

buildConfigField("String", "API_MIGRATED", "\"$apiMigrated\"")

javaCompileOptions {
annotationProcessorOptions {
arguments["room.schemaLocation"] = "$projectDir/schemas"
Expand All @@ -59,6 +52,10 @@ android {
"proguard-rules.pro"
)
}

create("ExperimentalServerDebug") {
initWith(buildTypes["debug"])
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
Expand Down Expand Up @@ -93,8 +90,8 @@ dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose)
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.ui)
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
Expand All @@ -104,14 +101,24 @@ dependencies {
implementation(libs.firebase.messaging.directboot)
implementation(libs.androidx.junit.ktx)
implementation(libs.protolite.well.known.types)
implementation(libs.firebase.analytics)

testImplementation(platform(libs.androidx.compose.bom))
testImplementation(libs.junit)
testImplementation(libs.kotlinx.coroutines.test) // Library to test coroutines in JUnit
testImplementation(libs.mockk)
testImplementation(libs.robolectric)
testImplementation(libs.androidx.compose.ui.test)

androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
androidTestImplementation(platform(libs.androidx.compose.bom))
androidTestImplementation(libs.mockk.android)
androidTestImplementation(libs.androidx.ui.test.junit4)

debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
debugImplementation(libs.androidx.compose.ui.test.manifest)

// Dagger
implementation(libs.dagger)
Expand All @@ -120,6 +127,11 @@ dependencies {
kapt(libs.dagger.compiler)
kapt(libs.dagger.android.processor)

// Dagger for Android Test
androidTestImplementation(libs.dagger)
androidTestImplementation(libs.dagger.compiler)
kaptAndroidTest(libs.dagger.compiler)

implementation(libs.kotlin.serialization)

// Coroutine for Android
Expand Down
45 changes: 22 additions & 23 deletions app/src/main/java/com/doyoonkim/knutice/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.doyoonkim.knutice
import android.Manifest
import android.app.AlarmManager
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.util.Log
Expand Down Expand Up @@ -32,23 +31,21 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.doyoonkim.common.navigation.NavRoutes
import com.doyoonkim.common.theme.KNUTICETheme
import com.doyoonkim.common.ui.PermissionRationaleComposable
import com.doyoonkim.common.R
import com.doyoonkim.common.di.AppPreferences
import com.doyoonkim.common.navigation.DeeplinkHandler
import com.doyoonkim.common.theme.onAnyBackground
import com.doyoonkim.common.theme.variantPurple
import com.doyoonkim.knutice.di.components.DaggerMainActivityComponent
import com.doyoonkim.knutice.di.components.DaggerSplashSceneComponent
import com.doyoonkim.knutice.di.util.DefaultSystemService
import com.doyoonkim.main.splash.KnuticeSplashScreen
import com.doyoonkim.main.viewmodel.SplashViewModel
import com.doyoonkim.notification.local.NotificationAlarmScheduler
import com.google.firebase.analytics.FirebaseAnalytics
import kotlinx.coroutines.delay
import javax.inject.Inject

Expand All @@ -65,6 +62,7 @@ class MainActivity : ComponentActivity() {
val appComponent = (application as MainApplication).appComponent
DaggerMainActivityComponent.factory().create(DefaultSystemService(appComponent))
.inject(this)
val analytics = appComponent.analytics()

super.onCreate(savedInstanceState)
receivedIntent.value = intent
Expand All @@ -76,7 +74,7 @@ class MainActivity : ComponentActivity() {
val context = LocalContext.current
navController = rememberNavController()

var lastProcessedIntent by remember { mutableStateOf<Int?>(receivedIntent.value.hashCode()) }
var lastProcessedIntent by remember { mutableStateOf<Int?>(null) }
var isDeeplinkInProcess by remember { mutableStateOf(false) }

var isPreProcessCompleted by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -170,16 +168,25 @@ class MainActivity : ComponentActivity() {
}
}

LaunchedEffect(receivedIntent.value) {
receivedIntent.value?.let { intent ->
if (intent.hashCode() != lastProcessedIntent && isPreProcessCompleted) {
isDeeplinkInProcess = true
lastProcessedIntent = intent.hashCode()

intent.data?.let { uri ->
navController.navigate(uri.navDestination())
LaunchedEffect(receivedIntent.value, isPreProcessCompleted) {
if (isPreProcessCompleted) {
receivedIntent.value?.let { intent ->
if (intent.hashCode() != lastProcessedIntent) {
isDeeplinkInProcess = true
lastProcessedIntent = intent.hashCode()

DeeplinkHandler.processIntent(intent) { service, uri ->
// Analytics
analytics.logEvent("CLICK_NOTIFICATION", Bundle().apply {
putString(FirebaseAnalytics.Param.CONTENT_TYPE, service)
putString(FirebaseAnalytics.Param.SOURCE, "PUSH")
putString(FirebaseAnalytics.Param.DESTINATION, uri)
})

navController.navigate(uri)
}
isDeeplinkInProcess = false
}
isDeeplinkInProcess = false
}
}
}
Expand All @@ -195,14 +202,6 @@ class MainActivity : ComponentActivity() {
receivedIntent.value = intent
}

private fun Uri.navDestination(): String {
return if (this.host != "service") {
NavRoutes.Home.route
} else {
this.encodedPath?.substring(1) ?: NavRoutes.Home.route
}
}

override fun onDestroy() {
super.onDestroy()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.doyoonkim.knutice.analytics

import android.os.Bundle
import com.google.firebase.analytics.FirebaseAnalytics
import javax.inject.Inject

interface AnalyticsLogger {
fun logEvent(event: String, param: Bundle? = null)
}

class FirebaseAnalyticsLogger @Inject constructor(
private val analytics: FirebaseAnalytics
) : AnalyticsLogger {

override fun logEvent(event: String, param: Bundle?) {
analytics.logEvent(event, param)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import android.content.Context
import android.content.SharedPreferences
import com.doyoonkim.common.di.ApplicationContext
import com.doyoonkim.knutice.MainApplication
import com.doyoonkim.knutice.analytics.AnalyticsLogger
import com.doyoonkim.knutice.di.modules.AppModule
import com.doyoonkim.knutice.di.modules.FirebaseAnalyticsModule
import dagger.BindsInstance
import dagger.Component

@Component(
modules = [
AppModule::class
AppModule::class,
FirebaseAnalyticsModule::class
]
)
interface AppComponent {
Expand All @@ -26,6 +29,9 @@ interface AppComponent {
fun alarmManager(): AlarmManager
fun notificationManager(): NotificationManager

// Analytics
fun analytics(): AnalyticsLogger

@Component.Factory
interface Factory {
// provide AppComponent
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.doyoonkim.knutice.di.modules

import android.content.Context
import com.doyoonkim.common.di.ApplicationContext
import com.doyoonkim.knutice.analytics.AnalyticsLogger
import com.doyoonkim.knutice.analytics.FirebaseAnalyticsLogger
import com.google.firebase.analytics.FirebaseAnalytics
import dagger.Binds
import dagger.Module
import dagger.Provides

@Module
abstract class FirebaseAnalyticsModule {

companion object {
@Provides
fun providesAnalyticsInstance(@ApplicationContext context: Context) = FirebaseAnalytics.getInstance(context)
}

@Binds
abstract fun bindsFirebaseAnalyticsLogger(
impl: FirebaseAnalyticsLogger
): AnalyticsLogger

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.doyoonkim.knutice.navigation

import android.net.Uri
import android.os.Bundle
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.core.EaseIn
import androidx.compose.animation.core.EaseOut
Expand Down Expand Up @@ -47,6 +48,7 @@ import com.doyoonkim.main.viewmodel.NoticesInCategoryViewModel
import com.doyoonkim.main.viewmodel.NotificationPreferencesViewModel
import com.doyoonkim.main.viewmodel.SettingsViewModel
import com.doyoonkim.model.NoticeCategory
import com.google.firebase.analytics.FirebaseAnalytics

fun NavGraphBuilder.mainServiceNavGraph(
navController: NavController,
Expand All @@ -56,7 +58,7 @@ fun NavGraphBuilder.mainServiceNavGraph(
onBookmarkServiceRequested: (BookmarkInfo) -> Unit,
onExit: () -> Unit = { }
) {

val analytics = appComponent.analytics()

// ViewModels will be injected via ViewModelFactory
composable(NavRoutes.Home.route) {
Expand Down Expand Up @@ -88,6 +90,11 @@ fun NavGraphBuilder.mainServiceNavGraph(
onNoticeDetailRequested(NoticeDetail(id, url))
},
onTipClicked = { category, url ->
analytics.logEvent("BROWSE_TIP", Bundle().apply {
putString(FirebaseAnalytics.Param.ITEM_CATEGORY, category.name)
putString(FirebaseAnalytics.Param.SOURCE, "HomeScreen")
putString(FirebaseAnalytics.Param.DESTINATION, url)
})
navController.navigate("tipDetail/${category.name}/${Uri.encode(url)}")
}
)
Expand Down
3 changes: 3 additions & 0 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ android {
"proguard-rules.pro"
)
}
create("ExperimentalServerDebug") {
initWith(buildTypes["debug"])
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.doyoonkim.common.navigation

import android.content.Intent
import android.net.Uri

class DeeplinkHandler {
companion object {
fun processIntent(
intent: Intent,
onDestination: (service: String, uri: String) -> Unit
) {
var destination = NavRoutes.Home.route

if (intent.data != null) {
destination = intent.data!!.navDestination()
} else {
val id = intent.getStringExtra("nttId")
val url = intent.getStringExtra("contentUrl")

if (id != null && url != null) {
destination = generateNoticeUri(id, url)
}
}

val service = destination.split("/")[0]
onDestination(service, destination)
}

private fun Uri.navDestination(): String {
return if (this.host != "service") {
NavRoutes.Home.route
} else {
this.encodedPath?.substring(1) ?: NavRoutes.Home.route
}
}

private fun generateNoticeUri(id: String, url: String) =
"noticeDetail/$id/${Uri.encode(url)}/${true}"
}
}
Loading
Loading