Skip to content

Commit 9af0beb

Browse files
authored
Release v1.3.8
Release v1.3.8
2 parents 41d2ad1 + 721d32d commit 9af0beb

File tree

115 files changed

+2385
-342
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+2385
-342
lines changed

app/build.gradle.kts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins {
77
alias(libs.plugins.googleServices)
88
alias(libs.plugins.hilt)
99
alias(libs.plugins.ksp)
10+
alias(libs.plugins.firebase.crashlytics)
1011
}
1112

1213
android {
@@ -17,8 +18,8 @@ android {
1718
minSdk = libs.versions.minSdk.get().toInt()
1819
targetSdk = libs.versions.targetSdk.get().toInt()
1920

20-
versionCode = 16
21-
versionName = "1.3.7"
21+
versionCode = 17
22+
versionName = "1.3.8"
2223

2324
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2425
}
@@ -66,6 +67,9 @@ dependencies {
6667
implementation(project(ProjectPaths.Core.PROJECT))
6768
implementation(project(ProjectPaths.Core.SCHOOL))
6869
implementation(project(ProjectPaths.Core.UI))
70+
implementation(project(ProjectPaths.Core.NOTIFICATION))
71+
implementation(project(ProjectPaths.Core.DEVICE))
72+
implementation(project(ProjectPaths.Core.WIDGET))
6973

7074
implementation(project(ProjectPaths.DATA))
7175
implementation(project(ProjectPaths.DATABASE))
@@ -123,4 +127,14 @@ dependencies {
123127
androidTestImplementation(libs.androidx.junit)
124128

125129
implementation(libs.app.update)
130+
131+
implementation(platform(libs.firebase.bom))
132+
implementation(libs.firebase.messaging)
133+
implementation(libs.firebase.analytics)
134+
implementation(libs.firebase.crashlytics)
135+
136+
implementation(libs.androidx.work.runtime.ktx)
137+
138+
implementation(libs.androidx.hilt.work)
139+
ksp(libs.androidx.hilt.compiler)
126140
}

app/src/main/AndroidManifest.xml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,41 @@
3838
<category android:name="android.intent.category.LAUNCHER" />
3939
</intent-filter>
4040
</activity>
41+
<service android:name=".service.DmsMessagingService"
42+
android:exported="true">
43+
<intent-filter>
44+
<action android:name="com.google.firebase.MESSAGING_EVENT" />
45+
</intent-filter>
46+
</service>
47+
<meta-data
48+
android:name="om.google.firebase.messaging.default_notification_icon"
49+
android:resource="@drawable/ic_logo_image"/>
50+
<meta-data
51+
android:name="com.google.firebase.messaging.default_notification_channel_id"
52+
android:value="@string/default_notification_channel_id" />
53+
54+
<receiver
55+
android:name="team.aliens.dms.android.core.widget.meal.MealWidgetReceiver"
56+
android:label="@string/today_meal"
57+
android:exported="true">
58+
<intent-filter>
59+
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
60+
</intent-filter>
61+
<meta-data
62+
android:name="android.appwidget.provider"
63+
android:resource="@xml/big_meal_widget_provider"/>
64+
</receiver>
65+
66+
<provider
67+
android:name="androidx.startup.InitializationProvider"
68+
android:authorities="${applicationId}.androidx-startup"
69+
android:exported="false"
70+
tools:node="merge">
71+
<meta-data
72+
android:name="androidx.work.WorkManagerInitializer"
73+
android:value="androidx.startup"
74+
tools:node="remove" />
75+
</provider>
76+
4177
</application>
4278
</manifest>
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
package team.aliens.dms.android.app
22

33
import android.app.Application
4+
import androidx.hilt.work.HiltWorkerFactory
5+
import androidx.work.Configuration
46
import dagger.hilt.android.HiltAndroidApp
7+
import javax.inject.Inject
58

69
@HiltAndroidApp
7-
class DmsApplication : Application()
10+
class DmsApplication : Application(), Configuration.Provider {
11+
12+
@Inject
13+
lateinit var workFactory: HiltWorkerFactory
14+
15+
override val workManagerConfiguration: Configuration
16+
get() = Configuration.Builder()
17+
.setWorkerFactory(workFactory)
18+
.build()
19+
}

app/src/main/java/team/aliens/dms/android/app/MainActivity.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ import androidx.activity.compose.setContent
77
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
88
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
99
import androidx.core.view.WindowCompat
10+
import androidx.lifecycle.lifecycleScope
1011
import com.google.accompanist.adaptive.calculateDisplayFeatures
1112
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
1213
import com.google.android.play.core.install.model.AppUpdateType
1314
import com.google.android.play.core.install.model.UpdateAvailability
1415
import dagger.hilt.android.AndroidEntryPoint
16+
import kotlinx.coroutines.CoroutineScope
17+
import kotlinx.coroutines.Dispatchers
1518
import kotlinx.coroutines.flow.StateFlow
19+
import kotlinx.coroutines.launch
1620
import team.aliens.dms.android.core.designsystem.DmsTheme
1721
import team.aliens.dms.android.core.jwt.di.IsJwtAvailable
22+
import team.aliens.dms.android.core.notification.DeviceTokenManager
1823
import javax.inject.Inject
1924

2025
@AndroidEntryPoint
@@ -24,6 +29,9 @@ class MainActivity : ComponentActivity() {
2429
@Inject
2530
lateinit var isJwtAvailable: StateFlow<Boolean>
2631

32+
@Inject
33+
lateinit var deviceTokenManager: DeviceTokenManager
34+
2735
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
2836
override fun onCreate(savedInstanceState: Bundle?) {
2937
super.onCreate(savedInstanceState)
@@ -46,6 +54,10 @@ class MainActivity : ComponentActivity() {
4654
)
4755
}
4856
}
57+
58+
lifecycleScope.launch {
59+
deviceTokenManager.fetchDeviceToken()
60+
}
4961
}
5062

5163
private fun checkAppUpdate() {
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package team.aliens.dms.android.app
2+
3+
import android.annotation.SuppressLint
4+
import android.app.NotificationChannel
5+
import android.app.NotificationManager
6+
import android.app.PendingIntent
7+
import android.content.Context
8+
import android.content.Intent
9+
import android.os.Build
10+
import androidx.core.app.NotificationCompat
11+
import androidx.core.app.NotificationManagerCompat
12+
import team.aliens.dms.android.core.designsystem.DmsIcon
13+
import team.aliens.dms.android.core.notification.notificationPermissionGranted
14+
15+
private object Notifications {
16+
const val NOTIFICATION_ID = 0
17+
const val NOTIFICATION_CHANNEL_ID = "dms"
18+
const val CHANNEL_NAME = "dms"
19+
const val CHANNEL_DESCRIPTION = "dms notification channel"
20+
}
21+
22+
class NotificationManager(
23+
private val context: Context,
24+
) {
25+
26+
init {
27+
createNotificationChannel()
28+
}
29+
30+
private val notificationManagerCompat: NotificationManagerCompat by lazy {
31+
NotificationManagerCompat.from(context)
32+
}
33+
34+
private val messageId = System.currentTimeMillis().toInt()
35+
private val intent = Intent(context, MainActivity::class.java)
36+
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
37+
private val pendingIntent = PendingIntent.getActivity(
38+
context, messageId, intent, PendingIntent.FLAG_IMMUTABLE
39+
)
40+
41+
private val notificationBuilder: NotificationCompat.Builder by lazy {
42+
NotificationCompat.Builder(context, Notifications.NOTIFICATION_CHANNEL_ID)
43+
.setSmallIcon(DmsIcon.Notification)
44+
.setPriority(NotificationCompat.PRIORITY_HIGH)
45+
.setContentIntent(pendingIntent)
46+
}
47+
48+
fun setNotificationContent(
49+
title: String?,
50+
body: String?,
51+
) {
52+
notificationBuilder.run {
53+
title?.run { setContentTitle(this) }
54+
body?.run { setContentText(this) }
55+
}
56+
}
57+
58+
@SuppressLint("MissingPermission")
59+
fun sendNotification() {
60+
if (notificationPermissionGranted(context = context)) {
61+
notificationManagerCompat.notify(
62+
Notifications.NOTIFICATION_ID,
63+
notificationBuilder.build(),
64+
)
65+
}
66+
}
67+
68+
private fun createNotificationChannel() {
69+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
70+
val importance = NotificationManager.IMPORTANCE_DEFAULT
71+
val channel = NotificationChannel(
72+
Notifications.NOTIFICATION_CHANNEL_ID,
73+
Notifications.CHANNEL_NAME,
74+
importance
75+
).apply {
76+
this.description = Notifications.CHANNEL_DESCRIPTION
77+
}
78+
val notificationManager =
79+
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
80+
notificationManager.createNotificationChannel(channel)
81+
}
82+
}
83+
}

app/src/main/java/team/aliens/dms/android/app/navigation/DmsNavigator.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import team.aliens.dms.android.feature.destinations.FindIdScreenDestination
2222
import team.aliens.dms.android.feature.destinations.MainDestination
2323
import team.aliens.dms.android.feature.destinations.NoticeDetailsScreenDestination
2424
import team.aliens.dms.android.feature.destinations.NotificationBoxScreenDestination
25+
import team.aliens.dms.android.feature.destinations.NotificationSettingsScreenDestination
2526
import team.aliens.dms.android.feature.destinations.OutingApplicationScreenDestination
2627
import team.aliens.dms.android.feature.destinations.PointHistoryScreenDestination
2728
import team.aliens.dms.android.feature.destinations.RemainsApplicationScreenDestination
@@ -36,6 +37,7 @@ import team.aliens.dms.android.feature.destinations.StudyRoomDetailsScreenDestin
3637
import team.aliens.dms.android.feature.destinations.StudyRoomListScreenDestination
3738
import team.aliens.dms.android.feature.destinations.TermsScreenDestination
3839
import team.aliens.dms.android.feature.editpassword.navigation.EditPasswordNavGraph
40+
import team.aliens.dms.android.feature.notification.navigation.NotificationSettingsNavigator
3941
import team.aliens.dms.android.feature.outing.navigation.OutingNavGraph
4042
import team.aliens.dms.android.feature.resetpassword.navigation.ResetPasswordNavGraph
4143
import team.aliens.dms.android.feature.signup.navigation.SignUpNavGraph
@@ -46,10 +48,6 @@ class DmsNavigator(
4648
private val navController: NavController,
4749
) : AuthorizedNavigator, UnauthorizedNavigator {
4850

49-
override fun openNotificationBox() {
50-
navController.navigateSingleTop(NotificationBoxScreenDestination within navGraph)
51-
}
52-
5351
override fun openUnauthorizedNav() {
5452
navController.navigateSingleTop(UnauthorizedNavGraph) {
5553
popUpTo(AuthorizedNavGraph) {
@@ -58,6 +56,14 @@ class DmsNavigator(
5856
}
5957
}
6058

59+
override fun openSettingsNotification() {
60+
navController.navigateSingleTop(NotificationSettingsScreenDestination within navGraph)
61+
}
62+
63+
override fun openNotificationBox() {
64+
navController.navigateSingleTop(NotificationBoxScreenDestination within navGraph)
65+
}
66+
6167
override fun openStudyRoomList() {
6268
navController.navigateSingleTop(StudyRoomListScreenDestination within navGraph)
6369
}

app/src/main/java/team/aliens/dms/android/app/navigation/authorized/AuthorizedNavGraph.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import team.aliens.dms.android.feature.destinations.EditProfileImageScreenDestin
99
import team.aliens.dms.android.feature.destinations.MainDestination
1010
import team.aliens.dms.android.feature.destinations.NoticeDetailsScreenDestination
1111
import team.aliens.dms.android.feature.destinations.NotificationBoxScreenDestination
12+
import team.aliens.dms.android.feature.destinations.NotificationSettingsScreenDestination
1213
import team.aliens.dms.android.feature.destinations.PointHistoryScreenDestination
1314
import team.aliens.dms.android.feature.destinations.RemainsApplicationScreenDestination
1415
import team.aliens.dms.android.feature.destinations.StudyRoomDetailsScreenDestination
@@ -37,6 +38,7 @@ object AuthorizedNavGraph : NavGraphSpec {
3738
StudyRoomDetailsScreenDestination,
3839
NoticeDetailsScreenDestination,
3940
NotificationBoxScreenDestination,
41+
NotificationSettingsScreenDestination,
4042
PointHistoryScreenDestination,
4143
)
4244
.routedIn(navGraphSpec = this)

app/src/main/java/team/aliens/dms/android/app/navigation/authorized/AuthorizedNavigator.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import team.aliens.dms.android.feature.editpassword.navigation.EditPasswordNavig
44
import team.aliens.dms.android.feature.editprofile.navigation.EditProfileNavigator
55
import team.aliens.dms.android.feature.main.navigation.MainNavigator
66
import team.aliens.dms.android.feature.notice.navigation.NoticeNavigator
7-
import team.aliens.dms.android.feature.notification.navigation.NotificationNavigation
7+
import team.aliens.dms.android.feature.notification.navigation.NotificationBoxNavigator
8+
import team.aliens.dms.android.feature.notification.navigation.NotificationSettingsNavigator
89
import team.aliens.dms.android.feature.outing.navigation.OutingNavigator
910
import team.aliens.dms.android.feature.point.navigation.PointHistoryNavigator
1011
import team.aliens.dms.android.feature.remains.navigator.RemainsNavigator
@@ -15,7 +16,8 @@ interface AuthorizedNavigator :
1516
EditPasswordNavigator,
1617
EditProfileNavigator,
1718
NoticeNavigator,
18-
NotificationNavigation,
19+
NotificationBoxNavigator,
20+
NotificationSettingsNavigator,
1921
PointHistoryNavigator,
2022
RemainsNavigator,
2123
StudyRoomNavigator,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package team.aliens.dms.android.app.service
2+
3+
import com.google.firebase.messaging.FirebaseMessagingService
4+
import com.google.firebase.messaging.RemoteMessage
5+
import dagger.hilt.android.AndroidEntryPoint
6+
import kotlinx.coroutines.CoroutineScope
7+
import kotlinx.coroutines.Dispatchers
8+
import kotlinx.coroutines.launch
9+
import team.aliens.dms.android.core.notification.DeviceTokenManager
10+
import team.aliens.dms.android.app.NotificationManager
11+
import javax.inject.Inject
12+
13+
@AndroidEntryPoint
14+
class DmsMessagingService : FirebaseMessagingService() {
15+
16+
@Inject
17+
lateinit var deviceTokenManager: DeviceTokenManager
18+
19+
private val notificationManager: NotificationManager by lazy {
20+
NotificationManager(context = this)
21+
}
22+
23+
override fun onNewToken(deviceToken: String) {
24+
super.onNewToken(deviceToken)
25+
CoroutineScope(Dispatchers.IO).launch {
26+
deviceTokenManager.saveDeviceToken(deviceToken = deviceToken)
27+
}
28+
}
29+
30+
override fun onMessageReceived(message: RemoteMessage) {
31+
super.onMessageReceived(message)
32+
message.notification?.run {
33+
notificationManager.setNotificationContent(
34+
title = title,
35+
body = body,
36+
)
37+
}
38+
notificationManager.sendNotification()
39+
}
40+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
33
<string name="app_name" translatable="false">DMS</string>
4+
<string name="default_notification_channel_id">team.aliens.dms.android</string>
45
</resources>

0 commit comments

Comments
 (0)