From 43e7ee3584f70e1cfa035245feb0dee527010a4e Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 17:59:02 +0900
Subject: [PATCH 01/10] =?UTF-8?q?[feat]=20#107=20Firebase=20Crashlytics=20?=
=?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/build.gradle.kts | 2 ++
build.gradle.kts | 1 +
2 files changed, 3 insertions(+)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index d1ab406f..4e76bc14 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -8,6 +8,7 @@ plugins {
id("org.jetbrains.kotlin.kapt")
alias(libs.plugins.navigationSafeArgs)
id("com.google.gms.google-services")
+ id("com.google.firebase.crashlytics")
}
val properties = Properties().apply {
@@ -166,4 +167,5 @@ dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.4.0"))
implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-config-ktx")
+ implementation("com.google.firebase:firebase-crashlytics-ndk")
}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 309816ff..11f54c0d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,4 +5,5 @@ plugins {
alias(libs.plugins.dagger.hilt) apply false
alias(libs.plugins.navigationSafeArgs) apply false
id("com.google.gms.google-services") version "4.4.2" apply false
+ id("com.google.firebase.crashlytics") version "3.0.6" apply false
}
\ No newline at end of file
From 910976f3979b1d0aec1ad0e32bd60b24c0d60801 Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 18:07:17 +0900
Subject: [PATCH 02/10] =?UTF-8?q?[feat]=20#107=20Firebase=20=EC=9D=98?=
=?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EB=B2=84=EC=A0=84=20libs.version.toml=20?=
=?UTF-8?q?=EB=A1=9C=20=EC=B6=94=EC=B6=9C=20=EB=B0=8F=20kotlin=20=EB=B2=84?=
=?UTF-8?q?=EC=A0=84=20=EC=97=85=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/build.gradle.kts | 14 +++++++-------
build.gradle.kts | 4 ++--
gradle/libs.versions.toml | 30 +++++++++++++-----------------
3 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4e76bc14..76f37af5 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -4,11 +4,12 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.serialization)
+ alias(libs.plugins.kotlin.compose)
alias(libs.plugins.dagger.hilt)
id("org.jetbrains.kotlin.kapt")
alias(libs.plugins.navigationSafeArgs)
- id("com.google.gms.google-services")
- id("com.google.firebase.crashlytics")
+ alias(libs.plugins.googleServices)
+ alias(libs.plugins.firebaseCrashlytics)
}
val properties = Properties().apply {
@@ -78,7 +79,6 @@ android {
kotlinOptions {
jvmTarget = "11"
}
- composeOptions { kotlinCompilerExtensionVersion = "1.5.14" }
}
dependencies {
@@ -164,8 +164,8 @@ dependencies {
implementation(libs.accompanist.permissions)
// Firebase
- implementation(platform("com.google.firebase:firebase-bom:33.4.0"))
- implementation("com.google.firebase:firebase-analytics-ktx")
- implementation("com.google.firebase:firebase-config-ktx")
- implementation("com.google.firebase:firebase-crashlytics-ndk")
+ implementation(platform(libs.firebase.bom))
+ implementation(libs.firebase.analytics.ktx)
+ implementation(libs.firebase.config.ktx)
+ implementation(libs.firebase.crashlytics)
}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 11f54c0d..ebcb5dfd 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,6 +4,6 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.dagger.hilt) apply false
alias(libs.plugins.navigationSafeArgs) apply false
- id("com.google.gms.google-services") version "4.4.2" apply false
- id("com.google.firebase.crashlytics") version "3.0.6" apply false
+ alias(libs.plugins.googleServices) apply false
+ alias(libs.plugins.firebaseCrashlytics) apply false
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bd319424..0e29bbf2 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,11 +3,10 @@ accompanistPermissions = "0.37.3"
agp = "8.7.3"
coilCompose = "2.5.0"
composeBom = "2024.04.01"
-firebaseBom = "34.4.0"
-firebaseBomVersion = "33.4.0"
-firebaseConfig = "23.0.1"
-googleFirebaseBom = "33.3.0"
-kotlin = "1.9.24"
+firebaseBom = "34.6.0"
+firebaseCrashlytics = "3.0.6"
+googleServices = "4.4.2"
+kotlin = "2.0.21"
coreKtx = "1.15.0"
junit = "4.13.2"
junitVersion = "1.2.1"
@@ -37,8 +36,6 @@ playServicesLocation = "21.3.0"
cameraCore = "1.4.1"
kakao = "2.20.3"
material3Android = "1.3.2"
-firebaseCommonKtx = "22.0.1"
-
[libraries]
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" }
@@ -51,16 +48,13 @@ androidx-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" }
-firebase-analytics = { module = "com.google.firebase:firebase-analytics" }
-firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx" }
+
+# Firebase
firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom" }
-firebase-bom-v3330 = { module = "com.google.firebase:firebase-bom", version.ref = "googleFirebaseBom" }
-firebase-bom-v3340 = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBomVersion" }
-firebase-config = { module = "com.google.firebase:firebase-config" }
-firebase-config-ktx = { module = "com.google.firebase:firebase-config-ktx" }
-google-firebase-analytics = { module = "com.google.firebase:firebase-analytics" }
-google-firebase-config = { module = "com.google.firebase:firebase-config", version.ref = "firebaseConfig" }
-google-firebase-config-ktx = { module = "com.google.firebase:firebase-config-ktx" }
+firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics" }
+firebase-config-ktx = { module = "com.google.firebase:firebase-config" }
+firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics"}
+
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
@@ -101,14 +95,16 @@ kakao-friend = { group = "com.kakao.sdk", name = "v2-friend", version.ref = "kak
kakao-navi = { group = "com.kakao.sdk", name = "v2-navi", version.ref = "kakao" }
kakao-cert = { group = "com.kakao.sdk", name = "v2-cert", version.ref = "kakao" }
androidx-material3-android = { group = "androidx.compose.material3", name = "material3-android", version.ref = "material3Android" }
-firebase-common-ktx = { group = "com.google.firebase", name = "firebase-common-ktx", version.ref = "firebaseCommonKtx" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
+kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
dagger-hilt = { id = "com.google.dagger.hilt.android", version.ref = "daggerHilt" }
navigationSafeArgs = { id = "androidx.navigation.safeargs.kotlin", version.ref = "navigationFragmentKtx" }
+googleServices = { id = "com.google.gms.google-services", version.ref = "googleServices" }
+firebaseCrashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlytics" }
[bundles]
hilt = [
From c015ad251ecb6e47737e78ee287d2a2b28ae4a4c Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 20:30:36 +0900
Subject: [PATCH 03/10] =?UTF-8?q?[feat]=20#107=20Analytics=20=EB=AA=A8?=
=?UTF-8?q?=EB=93=88=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../kuit/findu/analytics/AnalyticsEvent.kt | 16 ++++++++++++
.../kuit/findu/analytics/AnalyticsHelper.kt | 5 ++++
.../findu/analytics/AnalyticsHelperImpl.kt | 21 ++++++++++++++++
.../kuit/findu/analytics/AnalyticsModule.kt | 25 +++++++++++++++++++
4 files changed, 67 insertions(+)
create mode 100644 app/src/main/java/com/kuit/findu/analytics/AnalyticsEvent.kt
create mode 100644 app/src/main/java/com/kuit/findu/analytics/AnalyticsHelper.kt
create mode 100644 app/src/main/java/com/kuit/findu/analytics/AnalyticsHelperImpl.kt
create mode 100644 app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsEvent.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsEvent.kt
new file mode 100644
index 00000000..bd63666a
--- /dev/null
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsEvent.kt
@@ -0,0 +1,16 @@
+package com.kuit.findu.analytics
+
+data class AnalyticsEvent(
+ val type: String,
+ val extras: List = emptyList(),
+) {
+ data class Param(
+ val key: String,
+ val value: String,
+ )
+
+ companion object {
+ const val SCREEN_VIEW = "screen_view" // TYPE
+ const val SCREEN_NAME = "screen_name" // EXTRA_KEY
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsHelper.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsHelper.kt
new file mode 100644
index 00000000..69716ff2
--- /dev/null
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsHelper.kt
@@ -0,0 +1,5 @@
+package com.kuit.findu.analytics
+
+interface AnalyticsHelper {
+ fun logEvent(event: AnalyticsEvent)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsHelperImpl.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsHelperImpl.kt
new file mode 100644
index 00000000..f79af806
--- /dev/null
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsHelperImpl.kt
@@ -0,0 +1,21 @@
+package com.kuit.findu.analytics
+
+import com.google.firebase.analytics.FirebaseAnalytics
+import com.google.firebase.analytics.logEvent
+import javax.inject.Inject
+
+class AnalyticsHelperImpl @Inject constructor(
+ private val firebaseAnalytics: FirebaseAnalytics,
+) : AnalyticsHelper {
+ override fun logEvent(event: AnalyticsEvent) {
+ firebaseAnalytics.logEvent(event.type) {
+ for (extra in event.extras) {
+ // Key, Value Max Length에 따른 slicing
+ param(
+ key = extra.key.take(40),
+ value = extra.value.take(100),
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
new file mode 100644
index 00000000..4eae2d30
--- /dev/null
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
@@ -0,0 +1,25 @@
+package com.kuit.findu.analytics
+
+import com.google.firebase.Firebase
+import com.google.firebase.analytics.FirebaseAnalytics
+import com.google.firebase.analytics.analytics
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import jakarta.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+abstract class AnalyticsModule {
+ @Binds
+ @Singleton
+ abstract fun bindsAnalyticsHelper(analyticsHelperImpl: AnalyticsHelperImpl): AnalyticsHelper
+
+ @Provides
+ @Singleton
+ fun provideFirebaseAnalytics(): FirebaseAnalytics {
+ return Firebase.analytics
+ }
+}
\ No newline at end of file
From 85eecfcc64dbb6ac39a104c5e7f269d1e404a3a3 Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 20:30:54 +0900
Subject: [PATCH 04/10] =?UTF-8?q?[feat]=20#107=20ScreenView=20=EB=A1=9C?=
=?UTF-8?q?=EA=B9=85=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../com/kuit/findu/analytics/AnalyticsExt.kt | 13 +++++++++++++
.../findu/presentation/ui/main/MainActivity.kt | 18 +++++++++++++-----
.../ui/report/WitnessReportFragment.kt | 2 +-
3 files changed, 27 insertions(+), 6 deletions(-)
create mode 100644 app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt
new file mode 100644
index 00000000..89f71728
--- /dev/null
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt
@@ -0,0 +1,13 @@
+package com.kuit.findu.analytics
+
+fun AnalyticsHelper.logScreenView(screenName: String) {
+ logEvent(
+ AnalyticsEvent(
+ type = AnalyticsEvent.SCREEN_VIEW,
+ extras = listOf(
+ AnalyticsEvent.Param(AnalyticsEvent.SCREEN_NAME, screenName),
+ ),
+ ),
+ )
+}
+
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt b/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt
index 4581d6f3..f1cc619f 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/main/MainActivity.kt
@@ -7,22 +7,22 @@ import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.kuit.findu.R
+import com.kuit.findu.analytics.AnalyticsHelper
+import com.kuit.findu.analytics.logScreenView
import com.kuit.findu.databinding.ActivityMainBinding
import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
-
+ @Inject
+ lateinit var analyticsHelper: AnalyticsHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
-
-
-
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
@@ -39,6 +39,14 @@ class MainActivity : AppCompatActivity() {
private fun setBottomNaviVisible(navController: NavController) {
navController.addOnDestinationChangedListener { _, destination, _ ->
+ val screenName = try {
+ resources.getResourceEntryName(destination.id)
+ } catch (_: Exception) {
+ "unknown_screen"
+ }
+
+ analyticsHelper.logScreenView(screenName)
+
binding.bnvMain.visibility = when (destination.id) {
R.id.fragment_home, R.id.fragment_search, R.id.fragment_info, R.id.fragment_my -> View.VISIBLE
R.id.fragment_search_detail_witness, R.id.fragment_search_detail_disappear, R.id.fragment_search_detail_protecting -> View.VISIBLE
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/report/WitnessReportFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/report/WitnessReportFragment.kt
index 629549e5..45a17d99 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/report/WitnessReportFragment.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/report/WitnessReportFragment.kt
@@ -59,7 +59,7 @@ class WitnessReportFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-
+
resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == AppCompatActivity.RESULT_OK) {
val data = result.data?.getStringExtra(ReportLocationDialog.Companion.POST_TAG)
From 7da7aff5bbd2cf6c24a5dd88c9af8a53c7c3a189 Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 20:53:22 +0900
Subject: [PATCH 05/10] =?UTF-8?q?[refactor]=20#107=20Provides=20=ED=95=A8?=
=?UTF-8?q?=EC=88=98=20companion=20object=20=EB=A1=9C=20=EC=9D=B4=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/com/kuit/findu/analytics/AnalyticsModule.kt | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
index 4eae2d30..bc16563c 100644
--- a/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
@@ -8,7 +8,7 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
-import jakarta.inject.Singleton
+import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
@@ -17,9 +17,11 @@ abstract class AnalyticsModule {
@Singleton
abstract fun bindsAnalyticsHelper(analyticsHelperImpl: AnalyticsHelperImpl): AnalyticsHelper
- @Provides
- @Singleton
- fun provideFirebaseAnalytics(): FirebaseAnalytics {
- return Firebase.analytics
+ companion object {
+ @Provides
+ @Singleton
+ fun provideFirebaseAnalytics(): FirebaseAnalytics {
+ return Firebase.analytics
+ }
}
}
\ No newline at end of file
From 959a602692a1b359729c3f4b4bf2c214320b48c6 Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 20:58:40 +0900
Subject: [PATCH 06/10] =?UTF-8?q?[feat]=20#107=20=ED=99=88=20=ED=99=94?=
=?UTF-8?q?=EB=A9=B4=EC=97=90=EC=84=9C=20=EC=A0=9C=EB=B3=B4=ED=95=98?=
=?UTF-8?q?=EA=B8=B0=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=98=EB=8A=94=20?=
=?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../presentation/ui/home/HomeFragment.kt | 50 +++++++++---
.../ui/home/viewmodel/HomeViewModel.kt | 81 ++++++++++++-------
2 files changed, 95 insertions(+), 36 deletions(-)
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/home/HomeFragment.kt b/app/src/main/java/com/kuit/findu/presentation/ui/home/HomeFragment.kt
index 93661b62..a5f2d68a 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/home/HomeFragment.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/home/HomeFragment.kt
@@ -36,7 +36,7 @@ class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
+ savedInstanceState: Bundle?,
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
@@ -76,11 +76,22 @@ class HomeFragment : Fragment() {
}
is HomeUiEffect.ShowToast -> {
- Toast.makeText(requireContext(), sideEffect.message, Toast.LENGTH_SHORT).show()
+ Toast.makeText(
+ requireContext(),
+ sideEffect.message,
+ Toast.LENGTH_SHORT
+ ).show()
}
- is HomeUiEffect.NavigateToProtectList -> TODO()
- is HomeUiEffect.NavigateToReportList -> TODO()
+ is HomeUiEffect.NavigateToProtectList -> {}
+ is HomeUiEffect.NavigateToReportList -> {}
+
+ is HomeUiEffect.NavigateToFindReport -> {
+ navigateToFindReport()
+ }
+ is HomeUiEffect.NavigateToLostReport -> {
+ navigateToLostReport()
+ }
is HomeUiEffect.Dial -> call120()
}
@@ -110,7 +121,11 @@ class HomeFragment : Fragment() {
homeViewModel.handleEvent(HomeUiEvent.OnAlarmButtonClick)
},
onIndicatorSelected = { reportDurationType ->
- homeViewModel.handleEvent(HomeUiEvent.OnHomeReportDurationClick(reportDurationType))
+ homeViewModel.handleEvent(
+ HomeUiEvent.OnHomeReportDurationClick(
+ reportDurationType
+ )
+ )
},
userNickname = uiState.nickname,
navigateToProtectDetail = { protectAnimal ->
@@ -128,13 +143,18 @@ class HomeFragment : Fragment() {
onReportDialogDismiss = {
homeViewModel.handleEvent(HomeUiEvent.OnReportDialogDismiss)
},
- onLostReportClick = {},
- onFindReportClick = {},
+ onLostReportClick = {
+ homeViewModel.navigateToLostReport()
+ },
+ onFindReportClick = {
+ homeViewModel.navigateToFindReport()
+ },
onPhoneClicked = {
homeViewModel.dial()
},
- navigateToHomeExtra = { homeExtraButtonType->
- navigateToHomeExtra(homeExtraButtonType) },
+ navigateToHomeExtra = { homeExtraButtonType ->
+ navigateToHomeExtra(homeExtraButtonType)
+ },
)
}
@@ -192,6 +212,18 @@ class HomeFragment : Fragment() {
}
}
+ private fun navigateToLostReport() {
+ findNavController().navigate(
+ HomeFragmentDirections.actionFragmentHomeToFragmentMissingReport()
+ )
+ }
+
+ private fun navigateToFindReport() {
+ findNavController().navigate(
+ HomeFragmentDirections.actionFragmentHomeToFragmentWitnessReport()
+ )
+ }
+
private fun openWebLink(url: String) {
val intent = Intent(Intent.ACTION_VIEW, url.toUri())
requireActivity().startActivity(intent)
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt
index 2b74cffe..47c5f3c9 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/home/viewmodel/HomeViewModel.kt
@@ -32,12 +32,16 @@ data class HomeUiState(
val bannerCurrentPage: Int = 0,
val isScrollToTopVisible: Boolean = false,
val isReportDialogVisible: Boolean = false,
- val locationPermission: Boolean = false
+ val locationPermission: Boolean = false,
) {
val userHomeUserStatusType: HomeUserStatusType
get() = when {
!locationPermission -> HomeUserStatusType.LOCATION_DENIED
- nickname.isEmpty() || nickname.equals(GUEST_NAME, ignoreCase = false) -> HomeUserStatusType.GUEST
+ nickname.isEmpty() || nickname.equals(
+ GUEST_NAME,
+ ignoreCase = false
+ ) -> HomeUserStatusType.GUEST
+
else -> HomeUserStatusType.MEMBER
}
}
@@ -68,6 +72,8 @@ sealed class HomeUiEffect {
data object NavigateToReportList : HomeUiEffect()
data class NavigateToProtectDetail(val animal: ProtectAnimal) : HomeUiEffect()
data class NavigateToReportDetail(val animal: ReportAnimal) : HomeUiEffect()
+ data object NavigateToLostReport : HomeUiEffect()
+ data object NavigateToFindReport : HomeUiEffect()
data class OpenWebLink(val url: String) : HomeUiEffect()
data class ShowToast(val message: String) : HomeUiEffect()
@@ -77,7 +83,7 @@ sealed class HomeUiEffect {
@HiltViewModel
class HomeViewModel @Inject constructor(
private val homeUseCase: GetHomeUseCase,
- private val getNicknameUseCase: GetNicknameUseCase
+ private val getNicknameUseCase: GetNicknameUseCase,
) : ViewModel() {
private val _uiState = MutableStateFlow(HomeUiState())
@@ -125,17 +131,21 @@ class HomeViewModel @Inject constructor(
_uiState.update { it.copy(loadState = LoadState.Loading) }
homeUseCase().fold(
onSuccess = { data ->
- _uiState.update { it.copy(
- loadState = LoadState.Success,
- homeData = data,
- errorMessage = null
- ) }
+ _uiState.update {
+ it.copy(
+ loadState = LoadState.Success,
+ homeData = data,
+ errorMessage = null
+ )
+ }
},
onFailure = { error ->
- _uiState.update { it.copy(
- loadState = LoadState.Error,
- errorMessage = error.message ?: "데이터를 불러오는 중 오류가 발생했습니다."
- ) }
+ _uiState.update {
+ it.copy(
+ loadState = LoadState.Error,
+ errorMessage = error.message ?: "데이터를 불러오는 중 오류가 발생했습니다."
+ )
+ }
}
)
}
@@ -154,29 +164,35 @@ class HomeViewModel @Inject constructor(
homeUseCase().fold(
onSuccess = { data ->
- _uiState.update { it.copy(
- loadState = LoadState.Success,
- homeData = data,
- errorMessage = null,
- isRefreshing = false
- ) }
+ _uiState.update {
+ it.copy(
+ loadState = LoadState.Success,
+ homeData = data,
+ errorMessage = null,
+ isRefreshing = false
+ )
+ }
},
onFailure = { error ->
- _uiState.update { it.copy(
- loadState = LoadState.Error,
- errorMessage = error.message ?: "데이터를 새로고침하는 중 오류가 발생했습니다.",
- isRefreshing = false
- ) }
+ _uiState.update {
+ it.copy(
+ loadState = LoadState.Error,
+ errorMessage = error.message ?: "데이터를 새로고침하는 중 오류가 발생했습니다.",
+ isRefreshing = false
+ )
+ }
}
)
}
}
private fun clearError() {
- _uiState.update { it.copy(
- errorMessage = null,
- loadState = if (_uiState.value.homeData != null) LoadState.Success else LoadState.Idle
- ) }
+ _uiState.update {
+ it.copy(
+ errorMessage = null,
+ loadState = if (_uiState.value.homeData != null) LoadState.Success else LoadState.Idle
+ )
+ }
}
@@ -215,6 +231,17 @@ class HomeViewModel @Inject constructor(
}
}
+ fun navigateToLostReport() {
+ viewModelScope.launch {
+ _uiEffect.send(HomeUiEffect.NavigateToLostReport)
+ }
+ }
+
+ fun navigateToFindReport() {
+ viewModelScope.launch {
+ _uiEffect.send(HomeUiEffect.NavigateToFindReport)
+ }
+ }
fun dial() {
viewModelScope.launch {
From c87f1bb0cf296a223b705fb2c2e87126e671c329 Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 21:04:38 +0900
Subject: [PATCH 07/10] =?UTF-8?q?[feat]=20#107=20=EC=9C=A0=EC=A0=80=20?=
=?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8,=20=ED=9A=8C=EC=9B=90=EA=B0=80?=
=?UTF-8?q?=EC=9E=85=20=EB=A1=9C=EA=B9=85=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../com/kuit/findu/analytics/AnalyticsExt.kt | 23 +++++++++++++++++++
.../ui/login/viewmodel/LoginViewModel.kt | 11 ++++++---
.../viewmodel/OnboardingViewModel.kt | 4 ++++
3 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt b/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt
index 89f71728..5c03728f 100644
--- a/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt
+++ b/app/src/main/java/com/kuit/findu/analytics/AnalyticsExt.kt
@@ -11,3 +11,26 @@ fun AnalyticsHelper.logScreenView(screenName: String) {
)
}
+fun AnalyticsHelper.logUserSignIn(userName: String, type: String) {
+ logEvent(
+ AnalyticsEvent(
+ type = "signed_in",
+ extras = listOf(
+ AnalyticsEvent.Param("user_name", userName),
+ AnalyticsEvent.Param("login_type", type),
+ ),
+ ),
+ )
+}
+
+fun AnalyticsHelper.logUserSignUp(userName: String) {
+ logEvent(
+ AnalyticsEvent(
+ type = "signed_in",
+ extras = listOf(
+ AnalyticsEvent.Param("user_name", userName),
+ AnalyticsEvent.Param("login_type", "Kakao"),
+ ),
+ ),
+ )
+}
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
index b7f70f43..b66b9233 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
@@ -3,6 +3,8 @@ package com.kuit.findu.presentation.ui.login.viewmodel
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.kuit.findu.analytics.AnalyticsHelper
+import com.kuit.findu.analytics.logUserSignIn
import com.kuit.findu.domain.usecase.SetNicknameUseCase
import com.kuit.findu.domain.usecase.auth.PostGuestLoginUseCase
import com.kuit.findu.domain.usecase.auth.PostLoginUseCase
@@ -19,7 +21,8 @@ class LoginViewModel @Inject constructor(
private val loginUseCase: PostLoginUseCase,
private val guestLoginUseCase: PostGuestLoginUseCase,
private val setAccessTokenUseCase: SetAccessTokenUseCase,
- private val setNicknameUseCase: SetNicknameUseCase
+ private val setNicknameUseCase: SetNicknameUseCase,
+ private val analyticsHelper: AnalyticsHelper,
) : ViewModel() {
private val _startMainActivity = MutableSharedFlow()
val startMainActivity: SharedFlow = _startMainActivity
@@ -34,6 +37,9 @@ class LoginViewModel @Inject constructor(
if (loginData.isFirstLogin) {
startOnboardingActivity(kakaoId = kakaoId)
} else {
+ analyticsHelper.logUserSignIn(
+ userName = loginData.userInfo?.nickname ?: "Null Nickname", type = "kakao"
+ )
setAccessTokenUseCase(accessToken = loginData.userInfo!!.accessToken)
setNicknameUseCase(nickname = loginData.userInfo.nickname)
startMainActivity()
@@ -44,11 +50,11 @@ class LoginViewModel @Inject constructor(
}
}
-
fun postGuestLogin(onSuccess: () -> Unit) {
viewModelScope.launch {
guestLoginUseCase.postGuestLogin()
.onSuccess { loginData ->
+ analyticsHelper.logUserSignIn(userName = GUEST_NAME, type = "Kakao")
setAccessTokenUseCase(accessToken = loginData.accessToken)
setNicknameUseCase(nickname = GUEST_NAME)
onSuccess()
@@ -61,7 +67,6 @@ class LoginViewModel @Inject constructor(
}
-
private fun startMainActivity() {
viewModelScope.launch {
_startMainActivity.emit(Unit)
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt
index b3a0e52a..779f3b49 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt
@@ -5,6 +5,8 @@ import android.net.Uri
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.kuit.findu.analytics.AnalyticsHelper
+import com.kuit.findu.analytics.logUserSignUp
import com.kuit.findu.domain.usecase.auth.PostCheckNicknameUseCase
import com.kuit.findu.domain.usecase.auth.PostSignupUseCase
import com.kuit.findu.presentation.type.DefaultProfileType
@@ -35,6 +37,7 @@ class OnboardingViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val postCheckNicknameUseCase: PostCheckNicknameUseCase,
private val postSignupUseCase: PostSignupUseCase,
+ private val analyticsHelper: AnalyticsHelper,
) : ViewModel() {
private val _uiState = MutableStateFlow(OnboardingUiState())
val uiState: StateFlow = _uiState.asStateFlow()
@@ -120,6 +123,7 @@ class OnboardingViewModel @Inject constructor(
nickname = uiState.value.nickname,
kakaoId = uiState.value.kakaoId
).onSuccess {
+ analyticsHelper.logUserSignUp(userName = uiState.value.nickname)
startMainActivity()
}.onFailure { e ->
Log.d("http", "Error Message: : $e")
From 8560e538f8c0c72fc5cba03d139f1bf1f95e9a6b Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 22:07:11 +0900
Subject: [PATCH 08/10] =?UTF-8?q?[feat]=20#107=20=ED=8C=8C=EC=9D=B4?=
=?UTF-8?q?=EC=96=B4=EB=B2=A0=EC=9D=B4=EC=8A=A4=20DI=20=EB=AA=A8=EB=93=88?=
=?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../{AnalyticsModule.kt => di/FirebaseModule.kt} | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
rename app/src/main/java/com/kuit/findu/analytics/{AnalyticsModule.kt => di/FirebaseModule.kt} (60%)
diff --git a/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt b/app/src/main/java/com/kuit/findu/analytics/di/FirebaseModule.kt
similarity index 60%
rename from app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
rename to app/src/main/java/com/kuit/findu/analytics/di/FirebaseModule.kt
index bc16563c..30fa006d 100644
--- a/app/src/main/java/com/kuit/findu/analytics/AnalyticsModule.kt
+++ b/app/src/main/java/com/kuit/findu/analytics/di/FirebaseModule.kt
@@ -1,8 +1,12 @@
-package com.kuit.findu.analytics
+package com.kuit.findu.analytics.di
import com.google.firebase.Firebase
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.google.firebase.crashlytics.crashlytics
+import com.kuit.findu.analytics.AnalyticsHelper
+import com.kuit.findu.analytics.AnalyticsHelperImpl
import dagger.Binds
import dagger.Module
import dagger.Provides
@@ -12,7 +16,7 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
-abstract class AnalyticsModule {
+abstract class FirebaseModule {
@Binds
@Singleton
abstract fun bindsAnalyticsHelper(analyticsHelperImpl: AnalyticsHelperImpl): AnalyticsHelper
@@ -23,5 +27,11 @@ abstract class AnalyticsModule {
fun provideFirebaseAnalytics(): FirebaseAnalytics {
return Firebase.analytics
}
+
+ @Provides
+ @Singleton
+ fun provideFirebaseCrashlytics(): FirebaseCrashlytics {
+ return Firebase.crashlytics
+ }
}
}
\ No newline at end of file
From 90c229e336a770ca994fe9cb54d84f46f09c768d Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 22:07:21 +0900
Subject: [PATCH 09/10] =?UTF-8?q?[feat]=20#107=20Api=20=EC=97=90=EB=9F=AC?=
=?UTF-8?q?=20=EB=A1=9C=EA=B9=85=EC=9A=A9=20=EC=9D=B8=ED=84=B0=EC=85=89?=
=?UTF-8?q?=ED=84=B0=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../util/ErrorTrackingInterceptor.kt | 45 +++++++++++++++++++
.../java/com/kuit/findu/di/NetworkModule.kt | 20 +++++++--
2 files changed, 61 insertions(+), 4 deletions(-)
create mode 100644 app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt
diff --git a/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt b/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt
new file mode 100644
index 00000000..8550122f
--- /dev/null
+++ b/app/src/main/java/com/kuit/findu/data/dataremote/util/ErrorTrackingInterceptor.kt
@@ -0,0 +1,45 @@
+package com.kuit.findu.data.dataremote.util
+
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.google.firebase.crashlytics.recordException
+import okhttp3.Interceptor
+import okhttp3.Response
+import javax.inject.Inject
+
+class ErrorTrackingInterceptor @Inject constructor(
+ private val firebaseCrashlytics: FirebaseCrashlytics,
+) : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val request = chain.request()
+ val response: Response
+
+ try {
+ response = chain.proceed(request)
+ } catch (e: Exception) {
+ // 1. 네트워크 자체가 끊긴 경우 등 (IOException)
+ firebaseCrashlytics.recordException(e)
+ throw e
+ }
+
+ // 2. 서버에서 응답은 왔으나 4xx, 5xx 에러인 경우
+ if (!response.isSuccessful) {
+ val code = response.code
+
+ val url = request.url.toString()
+
+ // Crashlytics에 상세 정보 기록
+ val exceptionMessage = when (response.code) {
+ in (400..499) -> "Client $code Error"
+ in (500..599) -> "Server $code Error"
+ else -> "Unknown $code Error"
+ }
+ firebaseCrashlytics.recordException(Exception(exceptionMessage)) {
+ key("api_method", request.method)
+ key("api_url", url)
+ key("api_status", code)
+ }
+ }
+
+ return response
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/kuit/findu/di/NetworkModule.kt b/app/src/main/java/com/kuit/findu/di/NetworkModule.kt
index 76021961..034b54f6 100644
--- a/app/src/main/java/com/kuit/findu/di/NetworkModule.kt
+++ b/app/src/main/java/com/kuit/findu/di/NetworkModule.kt
@@ -1,11 +1,13 @@
package com.kuit.findu.di
import android.content.Context
+import com.google.firebase.crashlytics.FirebaseCrashlytics
+import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.kuit.findu.BuildConfig
import com.kuit.findu.BuildConfig.DEBUG
import com.kuit.findu.data.datalocal.datasource.TokenLocalDataSource
import com.kuit.findu.data.dataremote.util.AuthInterceptor
-import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
+import com.kuit.findu.data.dataremote.util.ErrorTrackingInterceptor
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -39,13 +41,15 @@ object NetworkModule {
@Singleton
fun providesOkHttpClient(
loggingInterceptor: HttpLoggingInterceptor,
- authInterceptor: AuthInterceptor
+ authInterceptor: AuthInterceptor,
+ errorTrackingInterceptor: ErrorTrackingInterceptor,
): OkHttpClient =
OkHttpClient.Builder().apply {
connectTimeout(10, TimeUnit.SECONDS)
writeTimeout(10, TimeUnit.SECONDS)
readTimeout(10, TimeUnit.SECONDS)
if (DEBUG) addInterceptor(loggingInterceptor)
+ else addInterceptor(errorTrackingInterceptor)
addInterceptor(authInterceptor)
}.build()
@@ -60,17 +64,25 @@ object NetworkModule {
@Singleton
fun provideAuthInterceptor(
tokenLocalDataSource: TokenLocalDataSource,
- @ApplicationContext context: Context
+ @ApplicationContext context: Context,
): AuthInterceptor {
return AuthInterceptor(tokenLocalDataSource, context)
}
+ @Provides
+ @Singleton
+ fun provideErrorTrackingInterceptor(
+ firebaseCrashlytics: FirebaseCrashlytics,
+ ): ErrorTrackingInterceptor {
+ return ErrorTrackingInterceptor(firebaseCrashlytics)
+ }
+
@ExperimentalSerializationApi
@Provides
@Singleton
fun providesRetrofit(
okHttpClient: OkHttpClient,
- json: Json
+ json: Json,
): Retrofit =
Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
From 21eaa2c02250c597e912069a1de0731f53ac69fc Mon Sep 17 00:00:00 2001
From: ikseong00 <127182222+ikseong00@users.noreply.github.com>
Date: Wed, 26 Nov 2025 22:16:08 +0900
Subject: [PATCH 10/10] =?UTF-8?q?[fix]=20#107=20=EA=B2=8C=EC=8A=A4?=
=?UTF-8?q?=ED=8A=B8=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=8B=9C=20=EB=A1=9C?=
=?UTF-8?q?=EA=B9=85=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 게스트 로그인 시 로깅 타입을 "Kakao"에서 "Guest"로 수정
---
.../findu/presentation/ui/login/viewmodel/LoginViewModel.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
index b66b9233..8480dd4d 100644
--- a/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
+++ b/app/src/main/java/com/kuit/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
@@ -54,7 +54,7 @@ class LoginViewModel @Inject constructor(
viewModelScope.launch {
guestLoginUseCase.postGuestLogin()
.onSuccess { loginData ->
- analyticsHelper.logUserSignIn(userName = GUEST_NAME, type = "Kakao")
+ analyticsHelper.logUserSignIn(userName = GUEST_NAME, type = "Guest")
setAccessTokenUseCase(accessToken = loginData.accessToken)
setNicknameUseCase(nickname = GUEST_NAME)
onSuccess()