Refactor notification destinations (#1709)

Co-authored-by: Rafał Borcz <RafalBO99@outlook.com>
This commit is contained in:
Michael 2022-01-28 13:43:56 +01:00 committed by GitHub
parent de9fcb9af9
commit daa7b54dab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 2578 additions and 189 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +1,10 @@
package io.github.wulkanowy.data.db package io.github.wulkanowy.data.db
import android.content.Context import android.content.Context
import androidx.room.AutoMigration import androidx.room.*
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.RoomDatabase.JournalMode.TRUNCATE import androidx.room.RoomDatabase.JournalMode.TRUNCATE
import androidx.room.TypeConverters import io.github.wulkanowy.data.db.dao.*
import io.github.wulkanowy.data.db.dao.AdminMessageDao import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.dao.NotificationDao
import io.github.wulkanowy.data.db.dao.RecipientDao
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
import io.github.wulkanowy.data.db.dao.SchoolDao
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.dao.StudentInfoDao
import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Notification
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentInfo
import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.db.migrations.* import io.github.wulkanowy.data.db.migrations.*
import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.AppInfo
import javax.inject.Singleton import javax.inject.Singleton
@ -108,6 +46,7 @@ import javax.inject.Singleton
autoMigrations = [ autoMigrations = [
AutoMigration(from = 44, to = 45), AutoMigration(from = 44, to = 45),
AutoMigration(from = 46, to = 47), AutoMigration(from = 46, to = 47),
AutoMigration(from = 47, to = 48),
], ],
version = AppDatabase.VERSION_SCHEMA, version = AppDatabase.VERSION_SCHEMA,
exportSchema = true exportSchema = true
@ -116,7 +55,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 47 const val VERSION_SCHEMA = 48
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf( fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(), Migration2(),

View File

@ -1,11 +1,14 @@
package io.github.wulkanowy.data.db package io.github.wulkanowy.data.db
import androidx.room.TypeConverter import androidx.room.TypeConverter
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.utils.toTimestamp import io.github.wulkanowy.utils.toTimestamp
import kotlinx.serialization.SerializationException import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.time.*
import java.util.*
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.Month import java.time.Month
@ -58,4 +61,11 @@ class Converters {
emptyList() // handle errors from old gson Pair serialized data emptyList() // handle errors from old gson Pair serialized data
} }
} }
@TypeConverter
fun destinationToString(destination: Destination) = json.encodeToString(destination)
@TypeConverter
fun stringToDestination(destination: String): Destination = json.decodeFromString(destination)
} }

View File

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import io.github.wulkanowy.services.sync.notifications.NotificationType import io.github.wulkanowy.services.sync.notifications.NotificationType
import io.github.wulkanowy.ui.modules.Destination
import java.time.Instant import java.time.Instant
@Entity(tableName = "Notifications") @Entity(tableName = "Notifications")
@ -18,6 +19,9 @@ data class Notification(
val type: NotificationType, val type: NotificationType,
@ColumnInfo(defaultValue = "{\"type\":\"io.github.wulkanowy.ui.modules.Destination.Dashboard\"}")
val destination: Destination,
val date: Instant, val date: Instant,
val data: String? = null val data: String? = null

View File

@ -1,10 +1,10 @@
package io.github.wulkanowy.data.pojos package io.github.wulkanowy.data.pojos
import android.content.Intent
import io.github.wulkanowy.services.sync.notifications.NotificationType import io.github.wulkanowy.services.sync.notifications.NotificationType
import io.github.wulkanowy.ui.modules.Destination
data class NotificationData( data class NotificationData(
val intentToStart: Intent, val destination: Destination,
val title: String, val title: String,
val content: String val content: String
) )
@ -13,7 +13,7 @@ data class GroupNotificationData(
val notificationDataList: List<NotificationData>, val notificationDataList: List<NotificationData>,
val title: String, val title: String,
val content: String, val content: String,
val intentToStart: Intent, val destination: Destination,
val type: NotificationType val type: NotificationType
) )

View File

@ -0,0 +1,32 @@
package io.github.wulkanowy.data.serializers
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.nullable
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.time.LocalDate
@OptIn(ExperimentalSerializationApi::class)
object LocalDateSerializer : KSerializer<LocalDate?> {
override val descriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.LONG).nullable
override fun serialize(encoder: Encoder, value: LocalDate?) {
if (value == null) {
encoder.encodeNull()
} else {
encoder.encodeNotNullMark()
encoder.encodeLong(value.toEpochDay())
}
}
override fun deserialize(decoder: Decoder): LocalDate? =
if (decoder.decodeNotNullMark()) {
LocalDate.ofEpochDay(decoder.decodeLong())
} else {
decoder.decodeNull()
}
}

View File

@ -15,6 +15,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class ShortcutsHelper @Inject constructor(@ApplicationContext private val context: Context) { class ShortcutsHelper @Inject constructor(@ApplicationContext private val context: Context) {
// Destination cannot be used here as shortcuts
// require their intents to only use primitive types (see PersistableBundle.isValidType).
private val destinations = mapOf( private val destinations = mapOf(
"grade" to Destination.Grade, "grade" to Destination.Grade,
"attendance" to Destination.Attendance, "attendance" to Destination.Attendance,

View File

@ -14,6 +14,7 @@ import io.github.wulkanowy.data.pojos.GroupNotificationData
import io.github.wulkanowy.data.pojos.NotificationData import io.github.wulkanowy.data.pojos.NotificationData
import io.github.wulkanowy.data.repositories.NotificationRepository import io.github.wulkanowy.data.repositories.NotificationRepository
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.PendingIntentCompat import io.github.wulkanowy.utils.PendingIntentCompat
import io.github.wulkanowy.utils.getCompatBitmap import io.github.wulkanowy.utils.getCompatBitmap
import io.github.wulkanowy.utils.getCompatColor import io.github.wulkanowy.utils.getCompatColor
@ -47,7 +48,7 @@ class AppNotificationManager @Inject constructor(
PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
Random.nextInt(), Random.nextInt(),
notificationData.intentToStart, SplashActivity.getStartIntent(context, notificationData.destination),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
) )
) )
@ -92,7 +93,7 @@ class AppNotificationManager @Inject constructor(
PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
Random.nextInt(), Random.nextInt(),
notificationData.intentToStart, SplashActivity.getStartIntent(context, notificationData.destination),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
) )
) )
@ -146,7 +147,7 @@ class AppNotificationManager @Inject constructor(
PendingIntent.getActivity( PendingIntent.getActivity(
context, context,
Random.nextInt(), Random.nextInt(),
groupNotificationData.intentToStart, SplashActivity.getStartIntent(context, groupNotificationData.destination),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE
) )
) )
@ -168,6 +169,7 @@ class AppNotificationManager @Inject constructor(
studentId = student.id, studentId = student.id,
title = notificationData.title, title = notificationData.title,
content = notificationData.content, content = notificationData.content,
destination = notificationData.destination,
type = notificationType, type = notificationType,
date = Instant.now(), date = Instant.now(),
) )

View File

@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.pojos.GroupNotificationData import io.github.wulkanowy.data.pojos.GroupNotificationData
import io.github.wulkanowy.data.pojos.NotificationData import io.github.wulkanowy.data.pojos.NotificationData
import io.github.wulkanowy.ui.modules.Destination import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import java.time.Instant import java.time.Instant
@ -23,8 +22,9 @@ class ChangeTimetableNotification @Inject constructor(
suspend fun notify(items: List<Timetable>, student: Student) { suspend fun notify(items: List<Timetable>, student: Student) {
val currentTime = Instant.now() val currentTime = Instant.now()
val changedLessons = items.filter { (it.canceled || it.changes) && it.start > currentTime } val changedLessons = items.filter { (it.canceled || it.changes) && it.start > currentTime }
val notificationDataList = changedLessons.groupBy { it.date } val lessonsByDate = changedLessons.groupBy { it.date }
.map { (date, lessons) -> val notificationDataList = lessonsByDate
.flatMap { (date, lessons) ->
getNotificationContents(date, lessons).map { getNotificationContents(date, lessons).map {
NotificationData( NotificationData(
title = context.getPlural( title = context.getPlural(
@ -32,14 +32,10 @@ class ChangeTimetableNotification @Inject constructor(
1 1
), ),
content = it, content = it,
intentToStart = SplashActivity.getStartIntent(
context = context,
destination = Destination.Timetable(date) destination = Destination.Timetable(date)
) )
)
} }
} }
.flatten()
.ifEmpty { return } .ifEmpty { return }
val groupNotificationData = GroupNotificationData( val groupNotificationData = GroupNotificationData(
@ -53,7 +49,7 @@ class ChangeTimetableNotification @Inject constructor(
changedLessons.size, changedLessons.size,
changedLessons.size changedLessons.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Timetable()), destination = Destination.Timetable(lessonsByDate.toSortedMap().firstKey()),
type = NotificationType.CHANGE_TIMETABLE type = NotificationType.CHANGE_TIMETABLE
) )

View File

@ -31,7 +31,7 @@ class NewAttendanceNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.attendance_notify_new_items_title, 1), title = context.getPlural(R.plurals.attendance_notify_new_items_title, 1),
content = it, content = it,
intentToStart = SplashActivity.getStartIntent(context, Destination.Attendance) destination = Destination.Attendance
) )
} }
@ -46,7 +46,7 @@ class NewAttendanceNotification @Inject constructor(
notificationDataList.size, notificationDataList.size,
notificationDataList.size notificationDataList.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Attendance), destination = Destination.Attendance,
type = NotificationType.NEW_ATTENDANCE type = NotificationType.NEW_ATTENDANCE
) )

View File

@ -31,7 +31,7 @@ class NewConferenceNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.conference_notify_new_item_title, 1), title = context.getPlural(R.plurals.conference_notify_new_item_title, 1),
content = it, content = it,
intentToStart = SplashActivity.getStartIntent(context, Destination.Conference) destination = Destination.Conference
) )
} }
@ -43,7 +43,7 @@ class NewConferenceNotification @Inject constructor(
lines.size, lines.size,
lines.size lines.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Conference), destination = Destination.Conference,
type = NotificationType.NEW_CONFERENCE type = NotificationType.NEW_CONFERENCE
) )

View File

@ -31,7 +31,7 @@ class NewExamNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.exam_notify_new_item_title, 1), title = context.getPlural(R.plurals.exam_notify_new_item_title, 1),
content = it, content = it,
intentToStart = SplashActivity.getStartIntent(context, Destination.Exam), destination = Destination.Exam,
) )
} }
@ -43,7 +43,7 @@ class NewExamNotification @Inject constructor(
lines.size, lines.size,
lines.size lines.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Exam), destination = Destination.Exam,
type = NotificationType.NEW_EXAM type = NotificationType.NEW_EXAM
) )

View File

@ -26,7 +26,7 @@ class NewGradeNotification @Inject constructor(
append("${it.subject}: ${it.entry}") append("${it.subject}: ${it.entry}")
if (it.comment.isNotBlank()) append(" (${it.comment})") if (it.comment.isNotBlank()) append(" (${it.comment})")
}, },
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade), destination = Destination.Grade,
) )
} }
@ -34,7 +34,7 @@ class NewGradeNotification @Inject constructor(
notificationDataList = notificationDataList, notificationDataList = notificationDataList,
title = context.getPlural(R.plurals.grade_new_items, items.size), title = context.getPlural(R.plurals.grade_new_items, items.size),
content = context.getPlural(R.plurals.grade_notify_new_items, items.size, items.size), content = context.getPlural(R.plurals.grade_notify_new_items, items.size, items.size),
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade), destination = Destination.Grade,
type = NotificationType.NEW_GRADE_DETAILS type = NotificationType.NEW_GRADE_DETAILS
) )
@ -46,7 +46,7 @@ class NewGradeNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.grade_new_items_predicted, 1), title = context.getPlural(R.plurals.grade_new_items_predicted, 1),
content = "${it.subject}: ${it.predictedGrade}", content = "${it.subject}: ${it.predictedGrade}",
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade), destination = Destination.Grade,
) )
} }
@ -58,7 +58,7 @@ class NewGradeNotification @Inject constructor(
items.size, items.size,
items.size items.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade), destination = Destination.Grade,
type = NotificationType.NEW_GRADE_PREDICTED type = NotificationType.NEW_GRADE_PREDICTED
) )
@ -70,7 +70,7 @@ class NewGradeNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.grade_new_items_final, 1), title = context.getPlural(R.plurals.grade_new_items_final, 1),
content = "${it.subject}: ${it.finalGrade}", content = "${it.subject}: ${it.finalGrade}",
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade), destination = Destination.Grade,
) )
} }
@ -82,7 +82,7 @@ class NewGradeNotification @Inject constructor(
items.size, items.size,
items.size items.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Grade), destination = Destination.Grade,
type = NotificationType.NEW_GRADE_FINAL type = NotificationType.NEW_GRADE_FINAL
) )

View File

@ -31,7 +31,7 @@ class NewHomeworkNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.homework_notify_new_item_title, 1), title = context.getPlural(R.plurals.homework_notify_new_item_title, 1),
content = it, content = it,
intentToStart = SplashActivity.getStartIntent(context, Destination.Homework), destination = Destination.Homework,
) )
} }
@ -42,7 +42,7 @@ class NewHomeworkNotification @Inject constructor(
lines.size, lines.size,
lines.size lines.size
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.Homework), destination = Destination.Homework,
type = NotificationType.NEW_HOMEWORK, type = NotificationType.NEW_HOMEWORK,
notificationDataList = notificationDataList notificationDataList = notificationDataList
) )

View File

@ -22,7 +22,7 @@ class NewLuckyNumberNotification @Inject constructor(
R.string.lucky_number_notify_new_item, R.string.lucky_number_notify_new_item,
item.luckyNumber.toString() item.luckyNumber.toString()
), ),
intentToStart = SplashActivity.getStartIntent(context, Destination.LuckyNumber) destination = Destination.LuckyNumber
) )
appNotificationManager.sendSingleNotification( appNotificationManager.sendSingleNotification(

View File

@ -22,7 +22,7 @@ class NewMessageNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(R.plurals.message_new_items, 1), title = context.getPlural(R.plurals.message_new_items, 1),
content = "${it.sender}: ${it.subject}", content = "${it.sender}: ${it.subject}",
intentToStart = SplashActivity.getStartIntent(context, Destination.Message), destination = Destination.Message,
) )
} }
@ -30,7 +30,7 @@ class NewMessageNotification @Inject constructor(
notificationDataList = notificationDataList, notificationDataList = notificationDataList,
title = context.getPlural(R.plurals.message_new_items, items.size), title = context.getPlural(R.plurals.message_new_items, items.size),
content = context.getPlural(R.plurals.message_notify_new_items, items.size, items.size), content = context.getPlural(R.plurals.message_notify_new_items, items.size, items.size),
intentToStart = SplashActivity.getStartIntent(context, Destination.Message), destination = Destination.Message,
type = NotificationType.NEW_MESSAGE type = NotificationType.NEW_MESSAGE
) )

View File

@ -29,13 +29,13 @@ class NewNoteNotification @Inject constructor(
NotificationData( NotificationData(
title = context.getPlural(titleRes, 1), title = context.getPlural(titleRes, 1),
content = "${it.teacher}: ${it.category}", content = "${it.teacher}: ${it.category}",
intentToStart = SplashActivity.getStartIntent(context, Destination.Note), destination = Destination.Note,
) )
} }
val groupNotificationData = GroupNotificationData( val groupNotificationData = GroupNotificationData(
notificationDataList = notificationDataList, notificationDataList = notificationDataList,
intentToStart = SplashActivity.getStartIntent(context, Destination.Note), destination = Destination.Note,
title = context.getPlural(R.plurals.note_new_items, items.size), title = context.getPlural(R.plurals.note_new_items, items.size),
content = context.getPlural(R.plurals.note_notify_new_items, items.size, items.size), content = context.getPlural(R.plurals.note_notify_new_items, items.size, items.size),
type = NotificationType.NEW_NOTE type = NotificationType.NEW_NOTE

View File

@ -21,10 +21,7 @@ class NewSchoolAnnouncementNotification @Inject constructor(
suspend fun notify(items: List<SchoolAnnouncement>, student: Student) { suspend fun notify(items: List<SchoolAnnouncement>, student: Student) {
val notificationDataList = items.map { val notificationDataList = items.map {
NotificationData( NotificationData(
intentToStart = SplashActivity.getStartIntent( destination = Destination.SchoolAnnouncement,
context = context,
destination = Destination.SchoolAnnouncement
),
title = context.getPlural( title = context.getPlural(
R.plurals.school_announcement_notify_new_item_title, R.plurals.school_announcement_notify_new_item_title,
1 1
@ -34,10 +31,7 @@ class NewSchoolAnnouncementNotification @Inject constructor(
} }
val groupNotificationData = GroupNotificationData( val groupNotificationData = GroupNotificationData(
type = NotificationType.NEW_ANNOUNCEMENT, type = NotificationType.NEW_ANNOUNCEMENT,
intentToStart = SplashActivity.getStartIntent( destination = Destination.SchoolAnnouncement,
context = context,
destination = Destination.SchoolAnnouncement
),
title = context.getPlural( title = context.getPlural(
R.plurals.school_announcement_notify_new_item_title, R.plurals.school_announcement_notify_new_item_title,
items.size items.size

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.ui.modules package io.github.wulkanowy.ui.modules
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import io.github.wulkanowy.data.serializers.LocalDateSerializer
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
import io.github.wulkanowy.ui.modules.dashboard.DashboardFragment import io.github.wulkanowy.ui.modules.dashboard.DashboardFragment
@ -14,18 +15,19 @@ import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.schoolandteachers.school.SchoolFragment import io.github.wulkanowy.ui.modules.schoolandteachers.school.SchoolFragment
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
import java.io.Serializable import kotlinx.serialization.Serializable
import java.time.LocalDate import java.time.LocalDate
sealed interface Destination : Serializable { @Serializable
sealed class Destination private constructor() : java.io.Serializable {
/* /*
Type in children classes have to be as getter to avoid null in enums Type in children classes have to be as getter to avoid null in enums
https://stackoverflow.com/questions/68866453/kotlin-enum-val-is-returning-null-despite-being-set-at-compile-time https://stackoverflow.com/questions/68866453/kotlin-enum-val-is-returning-null-despite-being-set-at-compile-time
*/ */
val type: Type abstract val type: Type
val fragment: Fragment abstract val fragment: Fragment
enum class Type(val defaultDestination: Destination) { enum class Type(val defaultDestination: Destination) {
DASHBOARD(Dashboard), DASHBOARD(Dashboard),
@ -43,94 +45,84 @@ sealed interface Destination : Serializable {
MESSAGE(Message); MESSAGE(Message);
} }
object Dashboard : Destination { @Serializable
object Dashboard : Destination() {
override val type get() = Type.DASHBOARD override val type get() = Type.DASHBOARD
override val fragment get() = DashboardFragment.newInstance() override val fragment get() = DashboardFragment.newInstance()
} }
object Grade : Destination { @Serializable
object Grade : Destination() {
override val type get() = Type.GRADE override val type get() = Type.GRADE
override val fragment get() = GradeFragment.newInstance() override val fragment get() = GradeFragment.newInstance()
} }
object Attendance : Destination { @Serializable
object Attendance : Destination() {
override val type get() = Type.ATTENDANCE override val type get() = Type.ATTENDANCE
override val fragment get() = AttendanceFragment.newInstance() override val fragment get() = AttendanceFragment.newInstance()
} }
object Exam : Destination { @Serializable
object Exam : Destination() {
override val type get() = Type.EXAM override val type get() = Type.EXAM
override val fragment get() = ExamFragment.newInstance() override val fragment get() = ExamFragment.newInstance()
} }
data class Timetable(val date: LocalDate? = null) : Destination { @Serializable
data class Timetable(
@Serializable(with = LocalDateSerializer::class)
private val date: LocalDate? = null
) : Destination() {
override val type get() = Type.TIMETABLE override val type get() = Type.TIMETABLE
override val fragment get() = TimetableFragment.newInstance(date) override val fragment get() = TimetableFragment.newInstance(date)
} }
object Homework : Destination { @Serializable
object Homework : Destination() {
override val type get() = Type.HOMEWORK override val type get() = Type.HOMEWORK
override val fragment get() = HomeworkFragment.newInstance() override val fragment get() = HomeworkFragment.newInstance()
} }
object Note : Destination { @Serializable
object Note : Destination() {
override val type get() = Type.NOTE override val type get() = Type.NOTE
override val fragment get() = NoteFragment.newInstance() override val fragment get() = NoteFragment.newInstance()
} }
object Conference : Destination { @Serializable
object Conference : Destination() {
override val type get() = Type.CONFERENCE override val type get() = Type.CONFERENCE
override val fragment get() = ConferenceFragment.newInstance() override val fragment get() = ConferenceFragment.newInstance()
} }
object SchoolAnnouncement : Destination { @Serializable
object SchoolAnnouncement : Destination() {
override val type get() = Type.SCHOOL_ANNOUNCEMENT override val type get() = Type.SCHOOL_ANNOUNCEMENT
override val fragment get() = SchoolAnnouncementFragment.newInstance() override val fragment get() = SchoolAnnouncementFragment.newInstance()
} }
object School : Destination { @Serializable
object School : Destination() {
override val type get() = Type.SCHOOL override val type get() = Type.SCHOOL
override val fragment get() = SchoolFragment.newInstance() override val fragment get() = SchoolFragment.newInstance()
} }
object LuckyNumber : Destination { @Serializable
object LuckyNumber : Destination() {
override val type get() = Type.LUCKY_NUMBER override val type get() = Type.LUCKY_NUMBER
override val fragment get() = LuckyNumberFragment.newInstance() override val fragment get() = LuckyNumberFragment.newInstance()
} }
object More : Destination { @Serializable
object More : Destination() {
override val type get() = Type.MORE override val type get() = Type.MORE
override val fragment get() = MoreFragment.newInstance() override val fragment get() = MoreFragment.newInstance()
} }
object Message : Destination { @Serializable
object Message : Destination() {
override val type get() = Type.MESSAGE override val type get() = Type.MESSAGE
override val fragment get() = MessageFragment.newInstance() override val fragment get() = MessageFragment.newInstance()
} }
} }

View File

@ -25,8 +25,8 @@ private fun generateTimetable(subject: String, room: String, roomOld: String) =
diaryId = 0, diaryId = 0,
date = LocalDate.now().minusDays(Random.nextLong(0, 8)), date = LocalDate.now().minusDays(Random.nextLong(0, 8)),
number = 1, number = 1,
start = Instant.now(), start = Instant.now().plus(Duration.ofHours(1)),
end = Instant.now().plus(Duration.ofHours(1)), end = Instant.now(),
subjectOld = "", subjectOld = "",
group = "", group = "",
room = room, room = room,

View File

@ -7,14 +7,13 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.data.db.entities.Notification import io.github.wulkanowy.data.db.entities.Notification
import io.github.wulkanowy.databinding.ItemNotificationsCenterBinding import io.github.wulkanowy.databinding.ItemNotificationsCenterBinding
import io.github.wulkanowy.services.sync.notifications.NotificationType
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.toFormattedString
import javax.inject.Inject import javax.inject.Inject
class NotificationsCenterAdapter @Inject constructor() : class NotificationsCenterAdapter @Inject constructor() :
ListAdapter<Notification, NotificationsCenterAdapter.ViewHolder>(DiffUtilCallback()) { ListAdapter<Notification, NotificationsCenterAdapter.ViewHolder>(DiffUtilCallback()) {
var onItemClickListener: (NotificationType) -> Unit = {} var onItemClickListener: (Notification) -> Unit = {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
ItemNotificationsCenterBinding.inflate(LayoutInflater.from(parent.context), parent, false) ItemNotificationsCenterBinding.inflate(LayoutInflater.from(parent.context), parent, false)
@ -29,7 +28,7 @@ class NotificationsCenterAdapter @Inject constructor() :
notificationsCenterItemDate.text = item.date.toFormattedString("HH:mm, d MMM") notificationsCenterItemDate.text = item.date.toFormattedString("HH:mm, d MMM")
notificationsCenterItemIcon.setImageResource(item.type.icon) notificationsCenterItemIcon.setImageResource(item.type.icon)
root.setOnClickListener { onItemClickListener(item.type) } root.setOnClickListener { onItemClickListener(item) }
} }
} }

View File

@ -3,26 +3,14 @@ package io.github.wulkanowy.ui.modules.notificationscenter
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Notification import io.github.wulkanowy.data.db.entities.Notification
import io.github.wulkanowy.databinding.FragmentNotificationsCenterBinding import io.github.wulkanowy.databinding.FragmentNotificationsCenterBinding
import io.github.wulkanowy.services.sync.notifications.NotificationType
import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
import io.github.wulkanowy.ui.modules.exam.ExamFragment
import io.github.wulkanowy.ui.modules.grade.GradeFragment
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment
import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.note.NoteFragment
import io.github.wulkanowy.ui.modules.schoolannouncement.SchoolAnnouncementFragment
import io.github.wulkanowy.ui.modules.timetable.TimetableFragment
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -54,9 +42,8 @@ class NotificationsCenterFragment :
} }
override fun initView() { override fun initView() {
notificationsCenterAdapter.onItemClickListener = { notificationType -> notificationsCenterAdapter.onItemClickListener = { notification ->
notificationType.toDestinationFragment() (requireActivity() as MainActivity).pushView(notification.destination.fragment)
?.let { (requireActivity() as MainActivity).pushView(it) }
} }
with(binding.notificationsCenterRecycler) { with(binding.notificationsCenterRecycler) {
@ -93,20 +80,4 @@ class NotificationsCenterFragment :
presenter.onDetachView() presenter.onDetachView()
super.onDestroyView() super.onDestroyView()
} }
private fun NotificationType.toDestinationFragment(): Fragment? = when (this) {
NotificationType.NEW_CONFERENCE -> ConferenceFragment.newInstance()
NotificationType.NEW_EXAM -> ExamFragment.newInstance()
NotificationType.NEW_GRADE_DETAILS -> GradeFragment.newInstance()
NotificationType.NEW_GRADE_PREDICTED -> GradeFragment.newInstance()
NotificationType.NEW_GRADE_FINAL -> GradeFragment.newInstance()
NotificationType.NEW_HOMEWORK -> HomeworkFragment.newInstance()
NotificationType.NEW_LUCKY_NUMBER -> LuckyNumberFragment.newInstance()
NotificationType.NEW_MESSAGE -> MessageFragment.newInstance()
NotificationType.NEW_NOTE -> NoteFragment.newInstance()
NotificationType.NEW_ANNOUNCEMENT -> SchoolAnnouncementFragment.newInstance()
NotificationType.PUSH -> null
NotificationType.CHANGE_TIMETABLE -> TimetableFragment.newInstance()
NotificationType.NEW_ATTENDANCE -> AttendanceFragment.newInstance()
}
} }

View File

@ -48,7 +48,7 @@ class NotificationsCenterPresenter @Inject constructor(
emitAll(notificationRepository.getNotifications(studentId)) emitAll(notificationRepository.getNotifications(studentId))
} }
.map { notificationList -> notificationList.sortedByDescending { it.date } } .map { notificationList -> notificationList.sortedByDescending { it.date } }
.catch { Timber.i("Loading notifications result: An exception occurred") } .catch { Timber.i("Loading notifications result: An exception occurred: `$it`") }
.onEach { .onEach {
Timber.i("Loading notifications result: Success") Timber.i("Loading notifications result: Success")

View File

@ -7,6 +7,7 @@ import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.data.db.entities.Notification import io.github.wulkanowy.data.db.entities.Notification
import io.github.wulkanowy.data.repositories.NotificationRepository import io.github.wulkanowy.data.repositories.NotificationRepository
import io.github.wulkanowy.services.sync.notifications.NotificationType import io.github.wulkanowy.services.sync.notifications.NotificationType
import io.github.wulkanowy.ui.modules.Destination
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -38,6 +39,7 @@ class AppMessagingService : FirebaseMessagingService() {
data = customData, data = customData,
date = Instant.now(), date = Instant.now(),
type = NotificationType.PUSH, type = NotificationType.PUSH,
destination = Destination.Dashboard,
studentId = -1 studentId = -1
) )