Skip to content

Commit

Permalink
Merge pull request #314 from team-haribo/develop
Browse files Browse the repository at this point in the history
🔀 :: (#313) - release 1.2.9
  • Loading branch information
diejdkll authored Sep 9, 2024
2 parents 7d61c1c + 35e9e32 commit bb97e0b
Show file tree
Hide file tree
Showing 112 changed files with 440 additions and 363 deletions.
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ GOMS Android
┃ ┗ 📂activity
┣ 📂build-logic
┣ 📂core
┃ ┣ 📂analytice
┃ ┣ 📂common
┃ ┣ 📂data
┃ ┃ ┣ 📂di
Expand Down Expand Up @@ -82,16 +83,17 @@ GOMS Android
## :rocket: Tech Skills
| Tech Stack | |
|:-------------|:----------------------------------------------|
| Minimum SDK | 26 |
| Language | Kotlin |
| Architecture | MVVM, Android App Architecture |
| Async | Coroutine |
| Compose | Navigation, Kotlinx.Immutable |
| DI | Hilt |
| Image | Coil |
| Network | Retrofit2, OkHttp3 |
| Asynchronous | Coroutine, Flow |
| Jetpack | Proto DataStore, ViewModel |
| CI | Github Actions |
| ETC | Firebase Crashlytics, Firebase Analytics, FCM |

## :tada: Play Store
<a href="https://play.google.com/store/apps/details?id=com.goms.goms_android_v2"><img width="40%" src="https://play.google.com/intl/ko/badges/static/images/badges/ko_badge_web_generic.png"/></a>
<a href="https://play.google.com/store/apps/details?id=com.goms.goms_android_v2"><img width="40%" src="https://play.google.com/intl/ko/badges/static/images/badges/ko_badge_web_generic.png"/></a>
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ android {
}

dependencies {
implementation(project(":core:analytics"))
implementation(project(":core:common"))
implementation(project(":core:design-system"))
implementation(project(":core:datastore"))
Expand All @@ -35,5 +36,5 @@ dependencies {
androidTestImplementation(libs.androidx.test.ext)
implementation(libs.androidx.core.splashscreen)
implementation(libs.firebase.messaging)
implementation(libs.`in`.app.update)
implementation(libs.app.update.ktx)
}
29 changes: 19 additions & 10 deletions app/src/main/java/com/goms/goms_android_v2/GomsNotification.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@ import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Intent
import androidx.core.app.NotificationCompat
import com.goms.design_system.R
import com.goms.domain.notification.SaveDeviceTokenUseCase
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.goms.design_system.R
import com.goms.model.util.ResourceKeys
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class GomsNotification : FirebaseMessagingService() {
companion object {

@Inject
lateinit var saveDeviceTokenUseCase: SaveDeviceTokenUseCase

private companion object {
private const val CHANNEL_NAME = "GOMS"
private const val CHANNEL_DESCRIPTION = "GOMS NOTIFICATION"
private const val CHANNEL_ID = "goms_channel_id"
Expand All @@ -22,12 +32,16 @@ class GomsNotification : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
createNotificationChannel()
message.notification?.let { sendNotification(it.title, it.body) }
val title = message.data["title"].orEmpty()
val body = message.data["body"].orEmpty()
sendNotification(title, body)
}

override fun onNewToken(token: String) {
super.onNewToken(token)
saveDeviceToken(token)
CoroutineScope(Dispatchers.IO).launch {
saveDeviceTokenUseCase(token)
}
}

private fun createNotificationChannel() {
Expand Down Expand Up @@ -64,9 +78,4 @@ class GomsNotification : FirebaseMessagingService() {
val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager?.notify(messageId, notificationBuilder.build())
}

private fun saveDeviceToken(token: String) {
val deviceTokenSF = getSharedPreferences(ResourceKeys.DEVICE_TOKEN, MODE_PRIVATE)
deviceTokenSF.edit().putString(ResourceKeys.DEVICE, token).apply()
}
}
33 changes: 9 additions & 24 deletions app/src/main/java/com/goms/goms_android_v2/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.lifecycleScope
import com.goms.common.result.Result
import com.goms.analytics.AnalyticsHelper
import com.goms.goms_android_v2.ui.GomsApp
import com.goms.model.util.ResourceKeys
import com.goms.ui.createToast
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.install.model.AppUpdateType
Expand All @@ -24,6 +23,7 @@ import com.google.firebase.messaging.FirebaseMessaging
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
Expand All @@ -35,6 +35,9 @@ class MainActivity : ComponentActivity() {
}
}

@Inject
lateinit var analyticsHelper: AnalyticsHelper

private val viewModel: MainActivityViewModel by viewModels()

@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
Expand Down Expand Up @@ -67,8 +70,9 @@ class MainActivity : ComponentActivity() {
windowSizeClass = calculateWindowSizeClass(this),
onLogout = { logout() },
onAlarmOff = { viewModel.deleteDeviceToken() },
onAlarmOn = { getNotification() },
onAlarmOn = { saveNotification() },
uiState = uiState,
analyticsHelper = analyticsHelper
)
}
}
Expand Down Expand Up @@ -104,30 +108,11 @@ class MainActivity : ComponentActivity() {
}
}

private fun getNotification() {
private fun saveNotification() {
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
val deviceTokenSF = getSharedPreferences(ResourceKeys.DEVICE_TOKEN, MODE_PRIVATE)
val deviceToken = task.result
if (deviceTokenSF.getString(ResourceKeys.DEVICE, ResourceKeys.EMPTY) == deviceToken) {
viewModel.saveDeviceToken(deviceToken = deviceToken)
setNotification(deviceToken = deviceToken)
}
}
}
}

private fun setNotification(deviceToken: String) {
lifecycleScope.launch {
viewModel.saveDeviceTokenUiState.collect {
when (it) {
is Result.Success -> {
val deviceTokenSF = getSharedPreferences(ResourceKeys.DEVICE_TOKEN, MODE_PRIVATE)
deviceTokenSF.edit().putString(ResourceKeys.DEVICE, deviceToken).apply()
}

is Result.Error, Result.Loading -> Unit
}
viewModel.saveDeviceToken(deviceToken = deviceToken)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.goms.common.result.Result
import com.goms.common.result.asResult
import com.goms.data.repository.account.AccountRepository
import com.goms.data.repository.auth.AuthRepository
import com.goms.data.repository.setting.SettingRepository
import com.goms.domain.auth.SaveTokenUseCase
import com.goms.domain.auth.TokenRefreshUseCase
import com.goms.domain.notification.DeleteDeviceTokenUseCase
import com.goms.domain.notification.SaveDeviceTokenUseCase
import com.goms.model.response.account.ProfileResponseModel
import com.goms.model.response.auth.LoginResponseModel
import com.goms.model.util.ResourceKeys
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -20,7 +18,6 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -66,6 +63,9 @@ class MainActivityViewModel @Inject constructor(
private val _saveDeviceTokenUiState = MutableStateFlow<Result<Unit>>(Result.Loading)
val saveDeviceTokenUiState = _saveDeviceTokenUiState.asStateFlow()

private val _deleteDeviceTokenUiState = MutableStateFlow<Result<Unit>>(Result.Loading)
val deleteDeviceTokenUiState = _deleteDeviceTokenUiState.asStateFlow()

private val _themeState = MutableStateFlow(ResourceKeys.EMPTY)
val themeState = _themeState.asStateFlow()

Expand All @@ -90,6 +90,15 @@ class MainActivityViewModel @Inject constructor(

fun deleteDeviceToken() = viewModelScope.launch {
deleteDeviceTokenUseCase()
.onSuccess {
it.catch { remoteError ->
_deleteDeviceTokenUiState.value = Result.Error(remoteError)
}.collect { result ->
_deleteDeviceTokenUiState.value = Result.Success(result)
}
}.onFailure {
_deleteDeviceTokenUiState.value = Result.Error(it)
}
}

fun deleteToken() = viewModelScope.launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ fun GomsNavHost(
qrcodeState = qrcodeState,
onOutingStatusClick = navController::navigateToOutingStatus,
onLateListClick = navController::navigateToLateList,
onStudentManagementClick = navController::navigateToStudentManagement,
onQrcodeClick = { role ->
if (role == Authority.ROLE_STUDENT) {
navController.navigateToQrScan()
Expand Down
8 changes: 6 additions & 2 deletions app/src/main/java/com/goms/goms_android_v2/ui/GomsApp.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package com.goms.goms_android_v2.ui

import android.util.Log
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.hilt.navigation.compose.hiltViewModel
import com.goms.analytics.AnalyticsHelper
import com.goms.analytics.LocalAnalyticsHelper
import com.goms.design_system.theme.GomsTheme
import com.goms.goms_android_v2.MainActivityUiState
import com.goms.goms_android_v2.MainActivityViewModel
Expand All @@ -25,6 +26,7 @@ fun GomsApp(
onAlarmOff: () -> Unit,
onAlarmOn: () -> Unit,
uiState: MainActivityUiState,
analyticsHelper: AnalyticsHelper,
viewModel: MainActivityViewModel = hiltViewModel(),
) {
val themeState by viewModel.themeState.collectAsState()
Expand All @@ -34,7 +36,9 @@ fun GomsApp(
if (alarmState == Switch.ON.value) onAlarmOn()

GomsTheme(themeMode = themeState) {
CompositionLocalProvider {
CompositionLocalProvider(
LocalAnalyticsHelper provides analyticsHelper
) {
GomsNavHost(
appState = appState,
qrcodeState = qrcodeState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ class AndroidApplicationConventionPlugin : Plugin<Project> {
applicationId = "com.goms.goms_android_v2"
minSdk = 26
targetSdk = 34
versionCode = 19
versionName = "1.2.8"
versionCode = 20
versionName = "1.2.9"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

vectorDrawables.useSupportLibrary = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class AndroidFeatureConventionPlugin : Plugin<Project> {
add("implementation", project(":core:domain"))
add("implementation", project(":core:common"))
add("implementation", project(":core:datastore"))
add("implementation", project(":core:analytics"))

add("implementation", libs.findLibrary("coil.kt").get())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

internal fun Project.configureKotlinAndroid(
commonExtension: CommonExtension<*, *, *, *, *>
Expand Down
1 change: 1 addition & 0 deletions core/analytics/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
17 changes: 17 additions & 0 deletions core/analytics/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
id("goms.android.core")
id("goms.android.hilt")
id("goms.android.compose")
}

android {
namespace = "com.goms.analytics"
}

dependencies {
implementation(libs.androidx.compose.runtime)

implementation(platform(libs.firebase.bom))
implementation(libs.firebase.analytics)
}
Empty file.
21 changes: 21 additions & 0 deletions core/analytics/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.goms.analytics

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.goms.analytics.test", appContext.packageName)
}
}
4 changes: 4 additions & 0 deletions core/analytics/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Loading

0 comments on commit bb97e0b

Please sign in to comment.