1
1
package dev.johnoreilly.confetti.work
2
2
3
3
import android.app.Notification
4
- import android.app.NotificationChannel
5
- import android.app.NotificationManager
6
4
import android.content.Context
7
- import android.graphics.BitmapFactory
8
5
import android.os.Build
9
6
import android.util.Log
10
- import androidx.core.app.NotificationCompat
11
7
import androidx.core.app.NotificationManagerCompat
12
8
import com.apollographql.cache.normalized.FetchPolicy
13
9
import dev.johnoreilly.confetti.ConfettiRepository
14
10
import dev.johnoreilly.confetti.auth.Authentication
15
- import dev.johnoreilly.confetti.fragment.SessionDetails
16
- import dev.johnoreilly.confetti.shared.R
11
+ import dev.johnoreilly.confetti.notifications.SessionNotificationBuilder
12
+ import dev.johnoreilly.confetti.notifications.SummaryNotificationBuilder
17
13
import dev.johnoreilly.confetti.utils.DateService
18
14
import dev.johnoreilly.confetti.work.NotificationSender.Selector
19
15
import kotlinx.coroutines.flow.first
16
+ import kotlin.random.Random
20
17
21
18
class SessionNotificationSender (
22
19
private val context : Context ,
@@ -25,14 +22,14 @@ class SessionNotificationSender(
25
22
private val notificationManager : NotificationManagerCompat ,
26
23
private val authentication : Authentication ,
27
24
): NotificationSender {
25
+ private val sessionNotificationBuilder = SessionNotificationBuilder (context)
26
+ private val summaryNotificationBuilder = SummaryNotificationBuilder (context)
28
27
29
28
override suspend fun sendNotification (selector : Selector ) {
30
29
val notificationsEnabled = notificationManager.areNotificationsEnabled()
31
30
32
- println (" notificationsEnabled" )
33
-
34
31
if (! notificationsEnabled) {
35
- // return
32
+ return
36
33
}
37
34
38
35
// If there is no signed-in user, skip.
@@ -88,74 +85,21 @@ class SessionNotificationSender(
88
85
89
86
// If there are multiple notifications, we create a summary to group them.
90
87
if (upcomingSessions.count() > 1 ) {
91
- sendNotification(SUMMARY_ID , createSummaryNotification(upcomingSessions))
88
+ sendNotification(SUMMARY_ID , summaryNotificationBuilder. createSummaryNotification(upcomingSessions, SUMMARY_ID ).build( ))
92
89
}
93
90
94
91
// We reverse the sessions to show early sessions first.
95
- for ((id, session) in upcomingSessions.reversed().withIndex()) {
96
- sendNotification(id, createNotification(session))
92
+ for (session in upcomingSessions.reversed()) {
93
+ val notificationId = Random .nextInt(Integer .MAX_VALUE / 2 , Integer .MAX_VALUE )
94
+ sendNotification(notificationId, sessionNotificationBuilder.createNotification(session, conferenceId, notificationId).build())
97
95
}
98
96
}
99
97
100
98
private fun createNotificationChannel () {
101
99
// Channels are only available on Android O+.
102
100
if (Build .VERSION .SDK_INT < Build .VERSION_CODES .O ) return
103
101
104
- val name = " Upcoming sessions"
105
- val importance = NotificationManager .IMPORTANCE_DEFAULT
106
- val channel = NotificationChannel (CHANNEL_ID , name, importance).apply {
107
- description = " "
108
- }
109
-
110
- notificationManager.createNotificationChannel(channel)
111
- }
112
-
113
- private fun createNotification (session : SessionDetails ): Notification {
114
- val largeIcon = BitmapFactory .decodeResource(
115
- context.resources,
116
- R .mipmap.ic_launcher_round
117
- )
118
-
119
- return NotificationCompat
120
- .Builder (context, CHANNEL_ID )
121
- .setSmallIcon(R .mipmap.ic_launcher_round)
122
- .setLargeIcon(largeIcon)
123
- .setContentTitle(session.title)
124
- .setContentText(" Starts at ${session.startsAt.time} in ${session.room?.name.orEmpty()} " )
125
- .setGroup(GROUP )
126
- .setAutoCancel(true )
127
- .setLocalOnly(false )
128
- .extend(NotificationCompat .WearableExtender ().setBridgeTag(" session:reminder" ))
129
- .build()
130
- }
131
-
132
- private fun createSummaryNotification (sessions : List <SessionDetails >): Notification {
133
- val largeIcon = BitmapFactory .decodeResource(
134
- context.resources,
135
- R .mipmap.ic_launcher_round
136
- )
137
-
138
- // Apply scope function is failing with an error:
139
- // InboxStyle.apply can only be called from within the same library group prefix.
140
- val style = NotificationCompat .InboxStyle ()
141
- .setBigContentTitle(" ${sessions.count()} upcoming sessions" )
142
-
143
- // We only show up to a limited number of sessions to avoid pollute the user notifications.
144
- for (session in sessions.take(4 )) {
145
- style.addLine(session.title)
146
- }
147
-
148
- return NotificationCompat
149
- .Builder (context, CHANNEL_ID )
150
- .setSmallIcon(R .mipmap.ic_launcher_round)
151
- .setLargeIcon(largeIcon)
152
- .setGroup(GROUP )
153
- .setGroupSummary(true )
154
- .setAutoCancel(true )
155
- .setLocalOnly(false )
156
- .setStyle(style)
157
- .extend(NotificationCompat .WearableExtender ().setBridgeTag(" session:summary" ))
158
- .build()
102
+ notificationManager.createNotificationChannel(sessionNotificationBuilder.createChannel().build())
159
103
}
160
104
161
105
private fun sendNotification (id : Int , notification : Notification ) {
@@ -167,8 +111,8 @@ class SessionNotificationSender(
167
111
}
168
112
169
113
companion object {
170
- private val CHANNEL_ID = " SessionNotification"
171
- private val GROUP = " dev.johnoreilly.confetti.SESSIONS_ALERT"
172
- private val SUMMARY_ID = 0
114
+ internal val CHANNEL_ID = " SessionNotification"
115
+ internal val GROUP = " dev.johnoreilly.confetti.SESSIONS_ALERT"
116
+ private val SUMMARY_ID = 10
173
117
}
174
118
}
0 commit comments