From 8dc358b0754c54afe168b894306da46c9e1fa3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 18 Oct 2019 22:12:40 +0200 Subject: [PATCH] [APIv2] Notifications - DB entity, move to APIv2. Add Server event sync and web push. --- .../pl/szczodrzynski/edziennik/Notifier.java | 29 +-- .../edziennik/api/v2/ApiService.kt | 57 +++-- .../edziennik/api/v2/DataNotifications.kt | 210 ++++++++++++++++++ .../szczodrzynski/edziennik/api/v2/Errors.kt | 3 +- .../edziennik/api/v2/ServerSync.kt | 179 +++++++++++++++ .../api/v2/events/ErrorReportTask.kt | 9 - .../api/v2/events/task/ErrorReportTask.kt | 26 +++ .../api/v2/events/task/NotifyTask.kt | 79 +++++++ .../edziennik/api/v2/librus/Librus.kt | 4 +- .../api/v2/mobidziennik/Mobidziennik.kt | 4 +- .../edziennik/api/v2/models/Data.kt | 32 ++- .../edziennik/api/v2/template/Template.kt | 4 +- .../edziennik/api/v2/vulcan/Vulcan.kt | 4 +- .../edziennik/data/api/Edziennik.java | 45 ++-- .../edziennik/data/db/AppDb.java | 28 ++- .../db/modules/notification/Notification.kt | 126 +++++++++++ .../modules/notification/NotificationDao.kt | 35 +++ .../data/db/modules/profiles/Profile.kt | 2 + .../edziennik/network/ServerRequest.java | 17 +- .../sync/MyFirebaseMessagingService.java | 18 +- .../edziennik/utils/models/Notification.java | 37 ++- app/src/main/res/values-en/strings.xml | 7 +- app/src/main/res/values/strings.xml | 9 +- 23 files changed, 865 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/DataNotifications.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ServerSync.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/ErrorReportTask.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/ErrorReportTask.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/NotifyTask.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/Notification.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/NotificationDao.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Notifier.java b/app/src/main/java/pl/szczodrzynski/edziennik/Notifier.java index fa13e360..7b316ed8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Notifier.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Notifier.java @@ -8,20 +8,21 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Build; +import android.util.Log; + import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; -import android.util.Log; import java.util.ArrayList; import java.util.Collections; import java.util.List; import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull; -import pl.szczodrzynski.edziennik.utils.models.Date; -import pl.szczodrzynski.edziennik.utils.models.Time; import pl.szczodrzynski.edziennik.receivers.BootReceiver; import pl.szczodrzynski.edziennik.sync.SyncJob; import pl.szczodrzynski.edziennik.sync.SyncService; +import pl.szczodrzynski.edziennik.utils.models.Date; +import pl.szczodrzynski.edziennik.utils.models.Time; import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT; import static androidx.core.app.NotificationCompat.PRIORITY_MAX; @@ -36,14 +37,14 @@ public class Notifier { private static String CHANNEL_GET_DATA_DESC; private static final String GROUP_KEY_GET_DATA = "pl.szczodrzynski.edziennik.GET_DATA"; - private static final int ID_NOTIFICATIONS = 1337002; - private static String CHANNEL_NOTIFICATIONS_NAME; - private static String CHANNEL_NOTIFICATIONS_DESC; + public static final int ID_NOTIFICATIONS = 1337002; + public static String CHANNEL_NOTIFICATIONS_NAME; + public static String CHANNEL_NOTIFICATIONS_DESC; public static final String GROUP_KEY_NOTIFICATIONS = "pl.szczodrzynski.edziennik.NOTIFICATIONS"; - private static final int ID_NOTIFICATIONS_QUIET = 1337002; - private static String CHANNEL_NOTIFICATIONS_QUIET_NAME; - private static String CHANNEL_NOTIFICATIONS_QUIET_DESC; + public static final int ID_NOTIFICATIONS_QUIET = 1337002; + public static String CHANNEL_NOTIFICATIONS_QUIET_NAME; + public static String CHANNEL_NOTIFICATIONS_QUIET_DESC; public static final String GROUP_KEY_NOTIFICATIONS_QUIET = "pl.szczodrzynski.edziennik.NOTIFICATIONS_QUIET"; private static final int ID_UPDATES = 1337003; @@ -52,9 +53,9 @@ public class Notifier { private static final String GROUP_KEY_UPDATES = "pl.szczodrzynski.edziennik.UPDATES"; private App app; - private NotificationManager notificationManager; + public NotificationManager notificationManager; private NotificationCompat.Builder getDataNotificationBuilder; - private int notificationColor; + public int notificationColor; Notifier(App _app) { this.app = _app; @@ -109,13 +110,13 @@ public class Notifier { return app.appConfig.quietHoursStart > 0 && now >= start && now <= end; } - private int getNotificationDefaults() { + public int getNotificationDefaults() { return (shouldBeQuiet() ? 0 : Notification.DEFAULT_ALL); } - private String getNotificationGroup() { + public String getNotificationGroup() { return shouldBeQuiet() ? GROUP_KEY_NOTIFICATIONS_QUIET : GROUP_KEY_NOTIFICATIONS; } - private int getNotificationPriority() { + public int getNotificationPriority() { return shouldBeQuiet() ? PRIORITY_DEFAULT : PRIORITY_MAX; } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt index d505afc5..6ec5b605 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt @@ -13,8 +13,13 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.api.v2.events.* +import pl.szczodrzynski.edziennik.api.v2.events.SyncErrorEvent +import pl.szczodrzynski.edziennik.api.v2.events.SyncFinishedEvent +import pl.szczodrzynski.edziennik.api.v2.events.SyncProfileFinishedEvent +import pl.szczodrzynski.edziennik.api.v2.events.SyncProgressEvent import pl.szczodrzynski.edziennik.api.v2.events.requests.* +import pl.szczodrzynski.edziennik.api.v2.events.task.ErrorReportTask +import pl.szczodrzynski.edziennik.api.v2.events.task.NotifyTask import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.api.v2.librus.Librus @@ -25,7 +30,7 @@ import pl.szczodrzynski.edziennik.api.v2.template.Template import pl.szczodrzynski.edziennik.api.v2.vulcan.Vulcan import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile -import pl.szczodrzynski.edziennik.utils.Utils.d +import kotlin.math.max import kotlin.math.min class ApiService : Service() { @@ -39,6 +44,7 @@ class ApiService : Service() { private val taskQueue = mutableListOf() private val errorList = mutableListOf() private var queueHasErrorReportTask = false + private var queueHasNotifyTask = false private var serviceClosed = false private var taskCancelled = false @@ -64,8 +70,13 @@ class ApiService : Service() { private val taskCallback = object : EdziennikCallback { override fun onCompleted() { edziennikInterface = null - if (!taskCancelled) { - EventBus.getDefault().post(SyncProfileFinishedEvent(taskProfileId)) + if (taskRunningObject is SyncProfileRequest) { + // post an event if this task is a sync, not e.g. first login or message getting + if (!taskCancelled) { + EventBus.getDefault().post(SyncProfileFinishedEvent(taskProfileId)) + } + // add a notifying task to create data notifications of this profile + addNotifyTask() } notification.setIdle().post() taskRunningObject = null @@ -86,6 +97,12 @@ class ApiService : Service() { errorList.add(apiError) apiError.throwable?.printStackTrace() if (apiError.isCritical) { + // if this error ends the sync, post an error notification + // if this is a sync task, create a notifying task + if (taskRunningObject is SyncProfileRequest) { + // add a notifying task to create data notifications of this profile + addNotifyTask() + } notification.setCriticalError().post() taskRunningObject = null taskRunning = false @@ -109,6 +126,18 @@ class ApiService : Service() { EventBus.getDefault().post(SyncProgressEvent(taskProfileId, taskProfileName, taskProgress, taskProgressRes)) notification.setProgressRes(taskProgressRes!!).post() } + + fun addNotifyTask() { + if (!queueHasNotifyTask) { + queueHasNotifyTask = true + taskQueue.add( + if (queueHasErrorReportTask) max(taskQueue.size-1, 0) else taskQueue.size, + NotifyTask().apply { + taskId = ++taskMaximumId + } + ) + } + } } /* _______ _ _ _ @@ -134,15 +163,17 @@ class ApiService : Service() { if (task is ErrorReportTask) { queueHasErrorReportTask = false - notification - .setCurrentTask(taskRunningId, null) - .setProgressRes(R.string.edziennik_notification_api_error_report_title) - .post() - errorList.forEach { error -> - d(TAG, "Error ${error.tag} profile ${error.profileId}: code ${error.errorCode}") - } - errorList.clear() - notification.setIdle().post() + task.run(notification, errorList) + taskRunningObject = null + taskRunning = false + taskRunningId = -1 + sync() + return + } + + if (task is NotifyTask) { + queueHasNotifyTask = false + task.run(app) taskRunningObject = null taskRunning = false taskRunningId = -1 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/DataNotifications.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/DataNotifications.kt new file mode 100644 index 00000000..73f6de4f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/DataNotifications.kt @@ -0,0 +1,210 @@ +package pl.szczodrzynski.edziennik.api.v2 + +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.api.v2.models.Data +import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance +import pl.szczodrzynski.edziennik.data.db.modules.events.Event +import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.* +import pl.szczodrzynski.edziennik.data.db.modules.messages.Message +import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_LUCKY_NUMBER +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_ANNOUNCEMENT +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_ATTENDANCE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_EVENT +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_GRADE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_HOMEWORK +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_MESSAGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_NOTICE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_TIMETABLE_LESSON_CHANGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle +import pl.szczodrzynski.edziennik.utils.models.Date + +class DataNotifications(val data: Data) { + companion object { + private const val TAG = "DataNotifications" + } + + val app = data.app + val profileId = data.profile?.id ?: -1 + val profileName = data.profile?.name ?: "" + val profile = data.profile + val loginStore = data.loginStore + + init { run { + if (profile == null) { + return@run + } + + for (change in app.db.lessonChangeDao().getNotNotifiedNow(profileId)) { + val text = app.getString(R.string.notification_lesson_change_format, change.changeTypeStr(app), if (change.lessonDate == null) "" else change.lessonDate!!.formattedString, change.subjectLongName) + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE), + text = text, + type = TYPE_TIMETABLE_LESSON_CHANGE, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_TIMETABLE, + addedDate = change.addedDate + ).addExtra("timetableDate", change.lessonDate?.value?.toLong()) + } + + for (event in app.db.eventDao().getNotNotifiedNow(profileId)) { + val text = if (event.type == Event.TYPE_HOMEWORK) + app.getString( + if (event.subjectLongName.isNullOrEmpty()) + R.string.notification_homework_no_subject_format + else + R.string.notification_homework_format, + event.subjectLongName, + event.eventDate.formattedString + ) + else + app.getString( + if (event.subjectLongName.isNullOrEmpty()) + R.string.notification_event_no_subject_format + else + R.string.notification_event_format, + event.typeName, + event.eventDate.formattedString, + event.subjectLongName + ) + val type = if (event.type == Event.TYPE_HOMEWORK) TYPE_NEW_HOMEWORK else TYPE_NEW_EVENT + data.notifications += Notification( + title = app.getNotificationTitle(type), + text = text, + type = type, + profileId = profileId, + profileName = profileName, + viewId = if (event.type == Event.TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA, + addedDate = event.addedDate + ).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong()) + } + + val today = Date.getToday() + val todayValue = today.value + profile.currentSemester = profile.dateToSemester(today) + + for (grade in app.db.gradeDao().getNotNotifiedNow(profileId)) { + val gradeName = when (grade.type) { + TYPE_SEMESTER1_PROPOSED, TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name) + TYPE_SEMESTER1_FINAL, TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name) + TYPE_YEAR_PROPOSED -> app.getString(R.string.grade_year_proposed_format_2, grade.name) + TYPE_YEAR_FINAL -> app.getString(R.string.grade_year_final_format_2, grade.name) + else -> grade.name + } + val text = app.getString(R.string.notification_grade_format, gradeName, grade.subjectLongName) + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_NEW_GRADE), + text = text, + type = TYPE_NEW_GRADE, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_GRADES, + addedDate = grade.addedDate + ).addExtra("gradeId", grade.id).addExtra("gradesSubjectId", grade.subjectId) + } + + for (notice in app.db.noticeDao().getNotNotifiedNow(profileId)) { + val noticeTypeStr = if (notice.type == Notice.TYPE_POSITIVE) app.getString(R.string.notification_notice_praise) else if (notice.type == Notice.TYPE_NEGATIVE) app.getString(R.string.notification_notice_warning) else app.getString(R.string.notification_notice_new) + val text = app.getString(R.string.notification_notice_format, noticeTypeStr, notice.teacherFullName, Date.fromMillis(notice.addedDate).formattedString) + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_NEW_NOTICE), + text = text, + type = TYPE_NEW_NOTICE, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_BEHAVIOUR, + addedDate = notice.addedDate + ).addExtra("noticeId", notice.id) + } + + for (attendance in app.db.attendanceDao().getNotNotifiedNow(profileId)) { + var attendanceTypeStr = app.getString(R.string.notification_type_attendance) + when (attendance.type) { + Attendance.TYPE_ABSENT -> attendanceTypeStr = app.getString(R.string.notification_absence) + Attendance.TYPE_ABSENT_EXCUSED -> attendanceTypeStr = app.getString(R.string.notification_absence_excused) + Attendance.TYPE_BELATED -> attendanceTypeStr = app.getString(R.string.notification_belated) + Attendance.TYPE_BELATED_EXCUSED -> attendanceTypeStr = app.getString(R.string.notification_belated_excused) + Attendance.TYPE_RELEASED -> attendanceTypeStr = app.getString(R.string.notification_release) + } + val text = app.getString( + if (attendance.subjectLongName.isNullOrEmpty()) + R.string.notification_attendance_no_lesson_format + else + R.string.notification_attendance_format, + attendanceTypeStr, + attendance.subjectLongName, + attendance.lessonDate.formattedString + ) + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_NEW_ATTENDANCE), + text = text, + type = TYPE_NEW_ATTENDANCE, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_ATTENDANCE, + addedDate = attendance.addedDate + ).addExtra("attendanceId", attendance.id).addExtra("attendanceSubjectId", attendance.subjectId) + } + + for (announcement in app.db.announcementDao().getNotNotifiedNow(profileId)) { + val text = app.context.getString(R.string.notification_announcement_format, announcement.subject) + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_NEW_ANNOUNCEMENT), + text = text, + type = TYPE_NEW_ANNOUNCEMENT, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_ANNOUNCEMENTS, + addedDate = announcement.addedDate + ).addExtra("announcementId", announcement.id) + } + + for (message in app.db.messageDao().getReceivedNotNotifiedNow(profileId)) { + val text = app.context.getString(R.string.notification_message_format, message.senderFullName, message.subject) + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_NEW_MESSAGE), + text = text, + type = TYPE_NEW_MESSAGE, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_MESSAGES, + addedDate = message.addedDate + ).addExtra("messageType", Message.TYPE_RECEIVED.toLong()).addExtra("messageId", message.id) + } + + val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId) + luckyNumbers?.removeAll { it.date < today } + luckyNumbers?.forEach { luckyNumber -> + val text = when { + luckyNumber.date.value == todayValue -> // LN for today + app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number) + luckyNumber.date.value == todayValue + 1 -> // LN for tomorrow + app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_tomorrow_format else R.string.notification_lucky_number_tomorrow_format, luckyNumber.number) + else -> // LN for later + app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_later_format else R.string.notification_lucky_number_later_format, luckyNumber.date.formattedString, luckyNumber.number) + } + data.notifications += Notification( + title = app.getNotificationTitle(TYPE_LUCKY_NUMBER), + text = text, + type = TYPE_LUCKY_NUMBER, + profileId = profileId, + profileName = profileName, + viewId = DRAWER_ITEM_HOME, + addedDate = luckyNumber.addedDate + ) + } + + data.db.metadataDao().setAllNotified(profileId, true) + }} +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt index 6b0df35a..229ff405 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt @@ -125,4 +125,5 @@ const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901 const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902 const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903 const val EXCEPTION_LIBRUS_API_REQUEST = 904 -const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 905 \ No newline at end of file +const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 905 +const val EXCEPTION_NOTIFY_AND_SYNC = 910 \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ServerSync.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ServerSync.kt new file mode 100644 index 00000000..7114501a --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ServerSync.kt @@ -0,0 +1,179 @@ +package pl.szczodrzynski.edziennik.api.v2 + +import pl.szczodrzynski.edziennik.App.APP_URL +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA +import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.api.v2.models.ApiError +import pl.szczodrzynski.edziennik.api.v2.models.Data +import pl.szczodrzynski.edziennik.data.api.AppError.CODE_APP_SERVER_ERROR +import pl.szczodrzynski.edziennik.data.db.modules.events.Event +import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK +import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore +import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_EVENT +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_HOMEWORK +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_SERVER_MESSAGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle +import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile +import pl.szczodrzynski.edziennik.getJsonArray +import pl.szczodrzynski.edziennik.getLong +import pl.szczodrzynski.edziennik.getString +import pl.szczodrzynski.edziennik.network.ServerRequest + +class ServerSync(val data: Data, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "ServerSync" + } + + val app = data.app + val profileId = data.profile?.id ?: -1 + val profileName = data.profile?.name ?: "" + val profile = data.profile + val loginStore = data.loginStore + + private fun getUsernameId(): String { + if (loginStore.data == null) { + return "NO_LOGIN_STORE" + } + if (profile?.studentData == null) { + return "NO_STUDENT_STORE" + } + return when (data.loginStore.type) { + LoginStore.LOGIN_TYPE_MOBIDZIENNIK -> loginStore.getLoginData("serverName", "MOBI_UN") + ":" + loginStore.getLoginData("username", "MOBI_UN") + ":" + profile.getStudentData("studentId", -1) + LoginStore.LOGIN_TYPE_LIBRUS -> profile.getStudentData("schoolName", "LIBRUS_UN") + ":" + profile.getStudentData("accountLogin", "LIBRUS_LOGIN_UN") + LoginStore.LOGIN_TYPE_IUCZNIOWIE -> loginStore.getLoginData("schoolName", "IUCZNIOWIE_UN") + ":" + loginStore.getLoginData("username", "IUCZNIOWIE_UN") + ":" + profile.getStudentData("registerId", -1) + LoginStore.LOGIN_TYPE_VULCAN -> profile.getStudentData("schoolName", "VULCAN_UN") + ":" + profile.getStudentData("studentId", -1) + LoginStore.LOGIN_TYPE_DEMO -> loginStore.getLoginData("serverName", "DEMO_UN") + ":" + loginStore.getLoginData("username", "DEMO_UN") + ":" + profile.getStudentData("studentId", -1) + else -> "TYPE_UNKNOWN" + } + } + + init { run { + if (profile?.registration != Profile.REGISTRATION_ENABLED) { + onSuccess() + return@run + } + + val request = ServerRequest( + app, + app.requestScheme+APP_URL+"main.php?sync", + "Edziennik2/REG", + profile, + data.loginStore.type, + getUsernameId() + ) + + if (profile.empty) { + request.setBodyParameter("first_run", "true") + } + + var hasNotifications = true + if (app.appConfig.webPushEnabled) { + data.notifications + .filterNot { it.posted } + .let { + if (it.isEmpty()) { + hasNotifications = false + null + } + else + it + }?.forEachIndexed { index, notification -> + if (notification.type != TYPE_NEW_SHARED_EVENT + && notification.type != TYPE_SERVER_MESSAGE + && notification.type != TYPE_NEW_SHARED_HOMEWORK) { + request.setBodyParameter("notify[$index][type]", notification.type.toString()) + request.setBodyParameter("notify[$index][title]", notification.title) + request.setBodyParameter("notify[$index][text]", notification.text) + } + } + } + + if ((!app.appConfig.webPushEnabled || !hasNotifications) && !profile.enableSharedEvents) { + onSuccess() + return@run + } + + val result = request.runSync() + + if (result == null) { + data.error(ApiError(TAG, CODE_APP_SERVER_ERROR) + .setCritical(false)) + onSuccess() + return@run + } + var apiResponse = result.toString() + if (result.getString("success") != "true") { + data.error(ApiError(TAG, CODE_APP_SERVER_ERROR) + .setCritical(false)) + onSuccess() + return@run + } + // HERE PROCESS ALL THE RECEIVED EVENTS + // add them to the profile and create appropriate notifications + result.getJsonArray("events")?.forEach { jEventEl -> + val event = jEventEl.asJsonObject + val teamCode = event.getString("team") + + // get the target Team from teamCode + val team = app.db.teamDao().getByCodeNow(profile.id, teamCode) + if (team != null) { + + // create the event from Json. Add the missing teamId and !!profileId!! + val eventObject = app.gson.fromJson(event.toString(), Event::class.java) + // proguard. disable for Event.class + if (eventObject.eventDate == null) { + apiResponse += "\n\nEventDate == null\n$event" + } + eventObject.profileId = profileId + eventObject.teamId = team.id + eventObject.addedManually = true + + if (eventObject.sharedBy == getUsernameId()) { + eventObject.sharedBy = "self" + eventObject.sharedByName = profile.studentNameLong + } + + val typeObject = app.db.eventTypeDao().getByIdNow(profileId, eventObject.type) + + app.db.eventDao().add(eventObject) + + val metadata = Metadata( + profileId, + if (eventObject.type == TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT, + eventObject.id, + profile.empty, + true, + event.getLong("addedDate") ?: 0 + ) + + val metadataId = app.db.metadataDao().add(metadata) + + // notify if the event is new and not first sync + if (metadataId != -1L && !profile.empty) { + val text = app.getString( + R.string.notification_shared_event_format, + eventObject.sharedByName, + if (typeObject != null) typeObject.name else "wydarzenie", + if (eventObject.eventDate == null) "???" else eventObject.eventDate.formattedString, + eventObject.topic + ) + val type = if (eventObject.type == TYPE_HOMEWORK) TYPE_NEW_SHARED_HOMEWORK else TYPE_NEW_SHARED_EVENT + data.notifications += Notification( + title = app.getNotificationTitle(type), + text = text, + type = type, + profileId = profileId, + profileName = profileName, + viewId = if (eventObject.type == TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA, + addedDate = metadata.addedDate + ).addExtra("eventId", eventObject.id).addExtra("eventDate", eventObject.eventDate.value.toLong()) + } + } + } + + onSuccess() + }} +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/ErrorReportTask.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/ErrorReportTask.kt deleted file mode 100644 index 444443d1..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/ErrorReportTask.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2019-10-1. - */ - -package pl.szczodrzynski.edziennik.api.v2.events - -import pl.szczodrzynski.edziennik.api.v2.models.ApiTask - -class ErrorReportTask : ApiTask(-1) \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/ErrorReportTask.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/ErrorReportTask.kt new file mode 100644 index 00000000..aa1a52cf --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/ErrorReportTask.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-1. + */ + +package pl.szczodrzynski.edziennik.api.v2.events.task + +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.api.v2.ApiService +import pl.szczodrzynski.edziennik.api.v2.EdziennikNotification +import pl.szczodrzynski.edziennik.api.v2.models.ApiError +import pl.szczodrzynski.edziennik.api.v2.models.ApiTask +import pl.szczodrzynski.edziennik.utils.Utils + +class ErrorReportTask : ApiTask(-1) { + fun run(notification: EdziennikNotification, errorList: MutableList) { + notification + .setCurrentTask(taskId, null) + .setProgressRes(R.string.edziennik_notification_api_error_report_title) + .post() + errorList.forEach { error -> + Utils.d(ApiService.TAG, "Error ${error.tag} profile ${error.profileId}: code ${error.errorCode}") + } + errorList.clear() + notification.setIdle().post() + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/NotifyTask.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/NotifyTask.kt new file mode 100644 index 00000000..753040a0 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/task/NotifyTask.kt @@ -0,0 +1,79 @@ +package pl.szczodrzynski.edziennik.api.v2.events.task + +import android.app.PendingIntent +import android.content.Intent +import android.os.Build +import androidx.core.app.NotificationCompat +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.api.v2.models.ApiTask +import pl.szczodrzynski.edziennik.utils.models.Notification +import kotlin.math.min + +class NotifyTask : ApiTask(-1) { + fun run(app: App) { + val list = app.db.notificationDao().getNotPostedNow() + val notificationList = list.subList(0, min(8, list.size)) + + var unreadCount = list.size + + for (notification in notificationList) { + val intent = Intent(app, MainActivity::class.java) + notification.fillIntent(intent) + val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0) + val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup) + // title, text, type, date + .setContentTitle(notification.title) + .setContentText(notification.text) + .setSubText(Notification.stringType(app, notification.type)) + .setWhen(notification.addedDate) + .setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type))) + // icon, color, lights, priority + .setSmallIcon(R.drawable.ic_notification) + .setColor(app.notifier.notificationColor) + .setLights(-0xff0001, 2000, 2000) + .setPriority(app.notifier.notificationPriority) + // channel, group, style + .setChannelId(app.notifier.notificationGroup) + .setGroup(app.notifier.notificationGroup) + .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) + .setStyle(NotificationCompat.BigTextStyle().bigText(notification.text)) + // intent, auto cancel + .setContentIntent(pendingIntent) + .setAutoCancel(true) + if (!app.notifier.shouldBeQuiet()) { + notificationBuilder.setDefaults(app.notifier.notificationDefaults) + } + app.notifier.notificationManager.notify(notification.id, notificationBuilder.build()) + } + + if (notificationList.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val intent = Intent(app, MainActivity::class.java) + intent.action = "android.intent.action.MAIN" + intent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS) + val pendingIntent = PendingIntent.getActivity(app, ID_NOTIFICATIONS, + intent, 0) + + val groupBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup) + .setSmallIcon(R.drawable.ic_notification) + .setColor(app.notifier.notificationColor) + .setContentTitle(app.getString(R.string.notification_new_notification_title_format, unreadCount)) + .setGroupSummary(true) + .setAutoCancel(true) + .setChannelId(app.notifier.notificationGroup) + .setGroup(app.notifier.notificationGroup) + .setLights(-0xff0001, 2000, 2000) + .setPriority(app.notifier.notificationPriority) + .setContentIntent(pendingIntent) + .setStyle(NotificationCompat.BigTextStyle()) + if (!app.notifier.shouldBeQuiet()) { + groupBuilder.setDefaults(app.notifier.notificationDefaults) + } + app.notifier.notificationManager.notify(ID_NOTIFICATIONS, groupBuilder.build()) + } + + app.db.notificationDao().setAllPosted() + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt index d8961e74..0e3d093e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt @@ -36,7 +36,9 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va private fun completed() { data.saveData() - callback.onCompleted() + data.notifyAndSyncEvents { + callback.onCompleted() + } } /* _______ _ _ _ _ _ diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt index dc1aa662..f94d7ec9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt @@ -36,7 +36,9 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto private fun completed() { data.saveData() - callback.onCompleted() + data.notifyAndSyncEvents { + callback.onCompleted() + } } /* _______ _ _ _ _ _ diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt index c32703d2..5b1eeed7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt @@ -5,8 +5,12 @@ import android.util.SparseArray import com.google.gson.JsonObject import im.wangchao.mhttp.Response import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.api.v2.DataNotifications +import pl.szczodrzynski.edziennik.api.v2.EXCEPTION_NOTIFY_AND_SYNC +import pl.szczodrzynski.edziennik.api.v2.ServerSync import pl.szczodrzynski.edziennik.api.v2.interfaces.EndpointCallback import pl.szczodrzynski.edziennik.data.api.AppError.* +import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement import pl.szczodrzynski.edziennik.data.db.modules.api.EndpointTimer import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance @@ -23,6 +27,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher @@ -38,6 +43,9 @@ import java.net.UnknownHostException import javax.net.ssl.SSLException open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) { + companion object { + private const val TAG = "Data" + } var fakeLogin = false @@ -85,6 +93,8 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) var endpointTimers = mutableListOf() + val notifications = mutableListOf() + val teacherList = LongSparseArray() val subjectList = LongSparseArray() val teamList = LongSparseArray() @@ -132,7 +142,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) val metadataList = mutableListOf() val messageMetadataList = mutableListOf() - val db by lazy { app.db } + val db: AppDb by lazy { app.db } init { clear() @@ -175,6 +185,8 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) if (profile == null) return // return on first login + profile.empty = false + db.profileDao().add(profile) db.loginStoreDao().add(loginStore) @@ -233,6 +245,20 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) db.metadataDao().setSeen(messageMetadataList) } + fun notifyAndSyncEvents(onSuccess: () -> Unit) { + try { + DataNotifications(this) + ServerSync(this) { + db.notificationDao().addAll(notifications) + onSuccess() + } + } + catch (e: Exception) { + error(ApiError(TAG, EXCEPTION_NOTIFY_AND_SYNC) + .withThrowable(e)) + } + } + fun setSyncNext(endpointId: Int, syncIn: Long? = null, viewId: Int? = null) { EndpointTimer(profile?.id ?: -1, endpointId).apply { syncedNow() @@ -257,7 +283,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) } fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) { - var code = when (throwable) { + val code = when (throwable) { is UnknownHostException, is SSLException, is InterruptedIOException -> CODE_NO_INTERNET is SocketTimeoutException -> CODE_TIMEOUT else -> when (response?.code()) { @@ -268,7 +294,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) error(ApiError(tag, code).apply { profileId = profile?.id ?: -1 }.withResponse(response).withThrowable(throwable).withApiResponse(apiResponse)) } fun error(tag: String, errorCode: Int, response: Response? = null, apiResponse: String? = null) { - var code = when (null) { + val code = when (null) { is UnknownHostException, is SSLException, is InterruptedIOException -> CODE_NO_INTERNET is SocketTimeoutException -> CODE_TIMEOUT else -> when (response?.code()) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt index 4f2f6580..b9949410 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt @@ -35,7 +35,9 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, private fun completed() { data.saveData() - callback.onCompleted() + data.notifyAndSyncEvents { + callback.onCompleted() + } } /* _______ _ _ _ _ _ diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/Vulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/Vulcan.kt index 5b2b6e79..60504a98 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/Vulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/Vulcan.kt @@ -35,7 +35,9 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va private fun completed() { data.saveData() - callback.onCompleted() + data.notifyAndSyncEvents { + callback.onCompleted() + } } /* _______ _ _ _ _ _ diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Edziennik.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Edziennik.java index 328aaa95..e21a12dc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Edziennik.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Edziennik.java @@ -40,8 +40,8 @@ import java.util.List; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.BuildConfig; -import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.MainActivity; +import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.WidgetTimetable; import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface; import pl.szczodrzynski.edziennik.data.api.interfaces.SyncCallback; @@ -62,11 +62,11 @@ import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeFull; import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile; import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull; import pl.szczodrzynski.edziennik.data.db.modules.teams.Team; -import pl.szczodrzynski.edziennik.utils.models.Date; -import pl.szczodrzynski.edziennik.utils.models.Notification; import pl.szczodrzynski.edziennik.network.ServerRequest; import pl.szczodrzynski.edziennik.sync.SyncJob; import pl.szczodrzynski.edziennik.utils.Themes; +import pl.szczodrzynski.edziennik.utils.models.Date; +import pl.szczodrzynski.edziennik.utils.models.Notification; import pl.szczodrzynski.edziennik.widgets.luckynumber.WidgetLuckyNumber; import pl.szczodrzynski.edziennik.widgets.notifications.WidgetNotifications; @@ -102,6 +102,19 @@ import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_ import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS; import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK; import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_VULCAN; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_AUTO_ARCHIVING; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_LUCKY_NUMBER; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_ANNOUNCEMENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_ATTENDANCE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_EVENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_GRADE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_HOMEWORK; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_MESSAGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_NOTICE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_SHARED_EVENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_SHARED_HOMEWORK; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_SERVER_MESSAGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_TIMETABLE_LESSON_CHANGE; import static pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.REGISTRATION_ENABLED; import static pl.szczodrzynski.edziennik.sync.SyncService.PROFILE_MAX_PROGRESS; import static pl.szczodrzynski.edziennik.utils.Utils.d; @@ -291,7 +304,7 @@ public class Edziennik { String text = app.getContext().getString(R.string.notification_lesson_change_format, change.changeTypeStr(app.getContext()), change.lessonDate == null ? "" : change.lessonDate.getFormattedString(), change.subjectLongName); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_TIMETABLE_LESSON_CHANGE) + .withType(TYPE_TIMETABLE_LESSON_CHANGE) .withFragmentRedirect(MainActivity.DRAWER_ITEM_TIMETABLE) .withLongExtra("timetableDate", change.lessonDate.getValue()) .withAddedDate(change.addedDate) @@ -305,7 +318,7 @@ public class Edziennik { text = app.getContext().getString(R.string.notification_event_format, event.typeName, event.eventDate.getFormattedString(), ns(app.getString(R.string.notification_event_no_subject), event.subjectLongName)); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(event.type == TYPE_HOMEWORK ? Notification.TYPE_NEW_HOMEWORK : Notification.TYPE_NEW_EVENT) + .withType(event.type == TYPE_HOMEWORK ? TYPE_NEW_HOMEWORK : TYPE_NEW_EVENT) .withFragmentRedirect(event.type == TYPE_HOMEWORK ? MainActivity.DRAWER_ITEM_HOMEWORK : MainActivity.DRAWER_ITEM_AGENDA) .withLongExtra("eventId", event.id) .withLongExtra("eventDate", event.eventDate.getValue()) @@ -342,7 +355,7 @@ public class Edziennik { String text = app.getContext().getString(R.string.notification_grade_format, gradeName, grade.subjectLongName); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_NEW_GRADE) + .withType(TYPE_NEW_GRADE) .withFragmentRedirect(MainActivity.DRAWER_ITEM_GRADES) .withLongExtra("gradesSubjectId", grade.subjectId) .withAddedDate(grade.addedDate) @@ -353,7 +366,7 @@ public class Edziennik { String text = app.getContext().getString(R.string.notification_notice_format, noticeTypeStr, notice.teacherFullName, Date.fromMillis(notice.addedDate).getFormattedString()); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_NEW_NOTICE) + .withType(TYPE_NEW_NOTICE) .withFragmentRedirect(MainActivity.DRAWER_ITEM_BEHAVIOUR) .withLongExtra("noticeId", notice.id) .withAddedDate(notice.addedDate) @@ -381,7 +394,7 @@ public class Edziennik { String text = app.getContext().getString(R.string.notification_attendance_format, attendanceTypeStr, attendance.subjectLongName, attendance.lessonDate.getFormattedString()); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_NEW_ATTENDANCE) + .withType(TYPE_NEW_ATTENDANCE) .withFragmentRedirect(MainActivity.DRAWER_ITEM_ATTENDANCE) .withLongExtra("attendanceId", attendance.id) .withAddedDate(attendance.addedDate) @@ -391,7 +404,7 @@ public class Edziennik { String text = app.getContext().getString(R.string.notification_announcement_format, announcement.subject); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_NEW_ANNOUNCEMENT) + .withType(TYPE_NEW_ANNOUNCEMENT) .withFragmentRedirect(MainActivity.DRAWER_ITEM_ANNOUNCEMENTS) .withLongExtra("announcementId", announcement.id) .withAddedDate(announcement.addedDate) @@ -401,7 +414,7 @@ public class Edziennik { String text = app.getContext().getString(R.string.notification_message_format, message.senderFullName, message.subject); app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_NEW_MESSAGE) + .withType(TYPE_NEW_MESSAGE) .withFragmentRedirect(MainActivity.DRAWER_ITEM_MESSAGES) .withLongExtra("messageType", Message.TYPE_RECEIVED) .withLongExtra("messageId", message.id) @@ -423,7 +436,7 @@ public class Edziennik { } app.notifier.add(new Notification(app.getContext(), text) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_LUCKY_NUMBER) + .withType(TYPE_LUCKY_NUMBER) .withFragmentRedirect(MainActivity.DRAWER_ITEM_HOME) ); oldLuckyNumber = profile.getLuckyNumber(); @@ -456,9 +469,9 @@ public class Edziennik { for (Notification notification : app.appConfig.notifications) { //Log.d(TAG, notification.text); if (!notification.notified) { - if (notification.type != Notification.TYPE_NEW_SHARED_EVENT - && notification.type != Notification.TYPE_SERVER_MESSAGE - && notification.type != Notification.TYPE_NEW_SHARED_HOMEWORK) // these are automatically sent to the browser by the server + if (notification.type != TYPE_NEW_SHARED_EVENT + && notification.type != TYPE_SERVER_MESSAGE + && notification.type != TYPE_NEW_SHARED_HOMEWORK) // these are automatically sent to the browser by the server { //Log.d(TAG, "Adding notify[" + position + "]"); syncRequest.setBodyParameter("notify[" + position + "][type]", Integer.toString(notification.type)); @@ -520,7 +533,7 @@ public class Edziennik { if (metadataId != -1 && !registerEmpty) { app.notifier.add(new Notification(app.getContext(), app.getString(R.string.notification_shared_event_format, event.sharedByName, type != null ? type.name : "wydarzenie", event.eventDate == null ? "nieznana data" : event.eventDate.getFormattedString(), event.topic)) .withProfileData(profile.getId(), profile.getName()) - .withType(event.type == TYPE_HOMEWORK ? Notification.TYPE_NEW_SHARED_HOMEWORK : Notification.TYPE_NEW_SHARED_EVENT) + .withType(event.type == TYPE_HOMEWORK ? TYPE_NEW_SHARED_HOMEWORK : TYPE_NEW_SHARED_EVENT) .withFragmentRedirect(event.type == TYPE_HOMEWORK ? MainActivity.DRAWER_ITEM_HOMEWORK : MainActivity.DRAWER_ITEM_AGENDA) .withLongExtra("eventDate", event.eventDate.getValue()) ); @@ -687,7 +700,7 @@ public class Edziennik { profile.setArchived(true); app.notifier.add(new Notification(app.getContext(), app.getString(R.string.profile_auto_archiving_format, profile.getName(), profile.getDateYearEnd().getFormattedString())) .withProfileData(profile.getId(), profile.getName()) - .withType(Notification.TYPE_AUTO_ARCHIVING) + .withType(TYPE_AUTO_ARCHIVING) .withFragmentRedirect(DRAWER_ITEM_HOME) .withLongExtra("autoArchiving", 1L) ); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.java index 5922b5bf..1ba10997 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.java @@ -52,6 +52,8 @@ import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata; import pl.szczodrzynski.edziennik.data.db.modules.metadata.MetadataDao; import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice; import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeDao; +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification; +import pl.szczodrzynski.edziennik.data.db.modules.notification.NotificationDao; import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile; import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileDao; import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject; @@ -88,7 +90,8 @@ import pl.szczodrzynski.edziennik.utils.models.Date; DebugLog.class, EndpointTimer.class, LessonRange.class, - Metadata.class}, version = 59) + Notification.class, + Metadata.class}, version = 60) @TypeConverters({ ConverterTime.class, ConverterDate.class, @@ -121,6 +124,7 @@ public abstract class AppDb extends RoomDatabase { public abstract DebugLogDao debugLogDao(); public abstract EndpointTimerDao endpointTimerDao(); public abstract LessonRangeDao lessonRangeDao(); + public abstract NotificationDao notificationDao(); public abstract MetadataDao metadataDao(); private static volatile AppDb INSTANCE; @@ -644,6 +648,25 @@ public abstract class AppDb extends RoomDatabase { database.execSQL("DROP TABLE _old_luckyNumbers;"); } }; + private static final Migration MIGRATION_59_60 = new Migration(59, 60) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase database) { + database.execSQL("CREATE TABLE notifications (\n" + + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n" + + " title TEXT NOT NULL,\n" + + " `text` TEXT NOT NULL,\n" + + " `type` INTEGER NOT NULL,\n" + + " profileId INTEGER DEFAULT NULL,\n" + + " profileName TEXT DEFAULT NULL,\n" + + " posted INTEGER NOT NULL DEFAULT 0,\n" + + " viewId INTEGER DEFAULT NULL,\n" + + " extras TEXT DEFAULT NULL,\n" + + " addedDate INTEGER NOT NULL\n" + + ");"); + + database.execSQL("ALTER TABLE profiles ADD COLUMN disabledNotifications TEXT DEFAULT NULL"); + } + }; public static AppDb getDatabase(final Context context) { @@ -700,7 +723,8 @@ public abstract class AppDb extends RoomDatabase { MIGRATION_55_56, MIGRATION_56_57, MIGRATION_57_58, - MIGRATION_58_59 + MIGRATION_58_59, + MIGRATION_59_60 ) .allowMainThreadQueries() //.fallbackToDestructiveMigration() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/Notification.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/Notification.kt new file mode 100644 index 00000000..39f3d37f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/Notification.kt @@ -0,0 +1,126 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-18. + */ + +package pl.szczodrzynski.edziennik.data.db.modules.notification + +import android.content.Context +import android.content.Intent +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_AUTO_ARCHIVING +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_ERROR +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_FEEDBACK_MESSAGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_GENERAL +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_LUCKY_NUMBER +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_ANNOUNCEMENT +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_ATTENDANCE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_EVENT +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_GRADE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_HOMEWORK +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_MESSAGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_NOTICE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_EVENT +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_SERVER_MESSAGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_TIMETABLE_CHANGED +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_TIMETABLE_LESSON_CHANGE +import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_UPDATE + +@Entity(tableName = "notifications") +data class Notification( + @PrimaryKey(autoGenerate = true) + val id: Int = 0, + + val title: String, + val text: String, + + val type: Int, + + val profileId: Int?, + val profileName: String?, + + var posted: Boolean = false, + + var viewId: Int? = null, + var extras: JsonObject? = null, + + val addedDate: Long = System.currentTimeMillis() +) { + companion object { + const val TYPE_GENERAL = 0 + const val TYPE_UPDATE = 1 + const val TYPE_ERROR = 2 + const val TYPE_TIMETABLE_CHANGED = 3 + const val TYPE_TIMETABLE_LESSON_CHANGE = 4 + const val TYPE_NEW_GRADE = 5 + const val TYPE_NEW_EVENT = 6 + const val TYPE_NEW_HOMEWORK = 10 + const val TYPE_NEW_SHARED_EVENT = 7 + const val TYPE_NEW_SHARED_HOMEWORK = 12 + const val TYPE_NEW_MESSAGE = 8 + const val TYPE_NEW_NOTICE = 9 + const val TYPE_NEW_ATTENDANCE = 13 + const val TYPE_SERVER_MESSAGE = 11 + const val TYPE_LUCKY_NUMBER = 14 + const val TYPE_NEW_ANNOUNCEMENT = 15 + const val TYPE_FEEDBACK_MESSAGE = 16 + const val TYPE_AUTO_ARCHIVING = 17 + } + + fun addExtra(key: String, value: Long?): Notification { + extras = extras ?: JsonObject() + extras?.addProperty(key, value) + return this + } + fun addExtra(key: String, value: String?): Notification { + extras = extras ?: JsonObject() + extras?.addProperty(key, value) + return this + } + + fun fillIntent(intent: Intent) { + if (profileId != -1) + intent.putExtra("profileId", profileId) + if (viewId != -1) + intent.putExtra("fragmentId", viewId) + try { + extras?.entrySet()?.forEach { (key, value) -> + if (!value.isJsonPrimitive) + return@forEach + val primitive = value.asJsonPrimitive + if (primitive.isNumber) { + intent.putExtra(key, primitive.asLong) + } else if (primitive.isString) { + intent.putExtra(key, primitive.asString) + } + } + } catch (e: NullPointerException) { + e.printStackTrace() + } + } +} + +fun Context.getNotificationTitle(type: Int): String { + return getString(when (type) { + TYPE_UPDATE -> R.string.notification_type_update + TYPE_ERROR -> R.string.notification_type_error + TYPE_TIMETABLE_CHANGED -> R.string.notification_type_timetable_change + TYPE_TIMETABLE_LESSON_CHANGE -> R.string.notification_type_timetable_lesson_change + TYPE_NEW_GRADE -> R.string.notification_type_new_grade + TYPE_NEW_EVENT -> R.string.notification_type_new_event + TYPE_NEW_HOMEWORK -> R.string.notification_type_new_homework + TYPE_NEW_SHARED_EVENT -> R.string.notification_type_new_shared_event + TYPE_NEW_MESSAGE -> R.string.notification_type_new_message + TYPE_NEW_NOTICE -> R.string.notification_type_notice + TYPE_NEW_ATTENDANCE -> R.string.notification_type_attendance + TYPE_SERVER_MESSAGE -> R.string.notification_type_server_message + TYPE_LUCKY_NUMBER -> R.string.notification_type_lucky_number + TYPE_FEEDBACK_MESSAGE -> R.string.notification_type_feedback_message + TYPE_NEW_ANNOUNCEMENT -> R.string.notification_type_new_announcement + TYPE_AUTO_ARCHIVING -> R.string.notification_type_auto_archiving + TYPE_GENERAL -> R.string.notification_type_general + else -> R.string.notification_type_general + }) +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/NotificationDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/NotificationDao.kt new file mode 100644 index 00000000..c08e7e6d --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/notification/NotificationDao.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-18. + */ + +package pl.szczodrzynski.edziennik.data.db.modules.notification + +import androidx.lifecycle.LiveData +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query + +@Dao +interface NotificationDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun add(notification: Notification) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun addAll(notificationList: List) + + @Query("DELETE FROM notifications WHERE profileId = :profileId") + fun clear(profileId: Int) + + @Query("SELECT * FROM notifications") + fun getAll(): LiveData> + + @Query("SELECT * FROM notifications") + fun getAllNow(): List + + @Query("SELECT * FROM notifications WHERE posted = 0 ORDER BY addedDate DESC") + fun getNotPostedNow(): List + + @Query("UPDATE notifications SET posted = 1 WHERE posted = 0") + fun setAllPosted() +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/Profile.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/Profile.kt index 24029bcb..82d07f86 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/Profile.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/Profile.kt @@ -84,6 +84,8 @@ open class Profile : IDrawerProfile { var changedEndpoints: List? = null + var disabledNotifications: List? = null + var lastFullSync: Long = 0 var lastReceiversSync: Long = 0 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/network/ServerRequest.java b/app/src/main/java/pl/szczodrzynski/edziennik/network/ServerRequest.java index 4d8f9a80..53be419d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/network/ServerRequest.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/network/ServerRequest.java @@ -16,6 +16,7 @@ import im.wangchao.mhttp.ThreadMode; import im.wangchao.mhttp.callback.JsonCallbackHandler; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.BuildConfig; +import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile; import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull; import pl.szczodrzynski.edziennik.utils.Utils; @@ -33,21 +34,25 @@ public class ServerRequest { } public ServerRequest(App app, String url, String source, ProfileFull profileFull) { + this(app, url, source, profileFull, profileFull == null ? -1 : profileFull.getLoginStoreType(), profileFull == null ? "" : profileFull.getUsernameId()); + } + + public ServerRequest(App app, String url, String source, Profile profile, int loginStoreType, String usernameId) { this.app = app; this.url = url; this.params = new ArrayList<>(); - this.username = (profileFull != null && profileFull.getRegistration() == REGISTRATION_ENABLED ? profileFull.getUsernameId() : app.deviceId); + this.username = (profile != null && profile.getRegistration() == REGISTRATION_ENABLED ? usernameId : app.deviceId); this.source = source; - if (profileFull != null && profileFull.getRegistration() == REGISTRATION_ENABLED) { - this.setBodyParameter("login_type", Integer.toString(profileFull.getLoginStoreType())); - this.setBodyParameter("name_long", profileFull.getStudentNameLong()); - this.setBodyParameter("name_short", profileFull.getStudentNameShort()); + if (profile != null && profile.getRegistration() == REGISTRATION_ENABLED) { + this.setBodyParameter("login_type", Integer.toString(loginStoreType)); + this.setBodyParameter("name_long", profile.getStudentNameLong()); + this.setBodyParameter("name_short", profile.getStudentNameShort()); //if (Looper.myLooper() == Looper.getMainLooper()) { if (Looper.getMainLooper().getThread() == Thread.currentThread()) { this.setBodyParameter("team_ids", "UI_THREAD"); } else { - this.setBodyParameter("team_ids", app.gson.toJson(app.db.teamDao().getAllCodesNow(profileFull.getId()))); + this.setBodyParameter("team_ids", app.gson.toJson(app.db.teamDao().getAllCodesNow(profile.getId()))); } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/sync/MyFirebaseMessagingService.java b/app/src/main/java/pl/szczodrzynski/edziennik/sync/MyFirebaseMessagingService.java index feae360f..312724b7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/sync/MyFirebaseMessagingService.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/sync/MyFirebaseMessagingService.java @@ -15,21 +15,25 @@ import java.util.List; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.BuildConfig; -import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.MainActivity; +import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.data.db.modules.events.Event; import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull; import pl.szczodrzynski.edziennik.data.db.modules.events.EventType; import pl.szczodrzynski.edziennik.data.db.modules.feedback.FeedbackMessage; import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull; import pl.szczodrzynski.edziennik.data.db.modules.teams.Team; +import pl.szczodrzynski.edziennik.network.ServerRequest; import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment; import pl.szczodrzynski.edziennik.utils.models.Notification; -import pl.szczodrzynski.edziennik.network.ServerRequest; import static pl.szczodrzynski.edziennik.App.APP_URL; import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK; import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_FEEDBACK_MESSAGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_SHARED_EVENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_SHARED_HOMEWORK; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_SERVER_MESSAGE; import static pl.szczodrzynski.edziennik.utils.Utils.d; import static pl.szczodrzynski.edziennik.utils.Utils.strToInt; @@ -175,7 +179,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService { case "message": app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message")) .withTitle(remoteMessage.getData().get("title")) - .withType(Notification.TYPE_SERVER_MESSAGE) + .withType(TYPE_SERVER_MESSAGE) .withFragmentRedirect(MainActivity.DRAWER_ITEM_NOTIFICATIONS) ); app.notifier.postAll(null); @@ -203,7 +207,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService { app.notifier.add(new Notification(app.getContext(), feedbackMessage.text) .withTitle(remoteMessage.getData().get("title")) - .withType(Notification.TYPE_FEEDBACK_MESSAGE) + .withType(TYPE_FEEDBACK_MESSAGE) .withFragmentRedirect(MainActivity.TARGET_FEEDBACK) ); app.notifier.postAll(null); @@ -225,7 +229,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService { }); app.notifier.add(new Notification(app.getContext(), remoteMessage.getData().get("message")) .withTitle(remoteMessage.getData().get("title")) - .withType(Notification.TYPE_FEEDBACK_MESSAGE) + .withType(TYPE_FEEDBACK_MESSAGE) .withFragmentRedirect(MainActivity.TARGET_FEEDBACK) ); app.notifier.postAll(null); @@ -279,7 +283,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService { EventType eventType = app.db.eventTypeDao().getByIdNow(profile.getId(), event.type); app.notifier.add(new Notification(app.getContext(), app.getString((oldEvent == null ? R.string.notification_shared_event_format : R.string.notification_shared_event_modified_format), event.sharedByName, eventType == null ? "wydarzenie" : eventType.name, event.eventDate.getFormattedString(), event.topic)) .withProfileData(profile.getId(), profile.getName()) - .withType(event.type == TYPE_HOMEWORK ? Notification.TYPE_NEW_SHARED_HOMEWORK : Notification.TYPE_NEW_SHARED_EVENT) + .withType(event.type == TYPE_HOMEWORK ? TYPE_NEW_SHARED_HOMEWORK : TYPE_NEW_SHARED_EVENT) .withFragmentRedirect(event.type == TYPE_HOMEWORK ? MainActivity.DRAWER_ITEM_HOMEWORK : MainActivity.DRAWER_ITEM_AGENDA) .withLongExtra("eventDate", event.eventDate.getValue()) ); @@ -298,7 +302,7 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService { if (oldEvent != null) { app.notifier.add(new Notification(app.getContext(), app.getString(R.string.notification_shared_event_removed_format, oldEvent.sharedByName, oldEvent.typeName, oldEvent.eventDate.getFormattedString(), oldEvent.topic)) .withProfileData(profile.getId(), profile.getName()) - .withType(oldEvent.type == TYPE_HOMEWORK ? Notification.TYPE_NEW_SHARED_HOMEWORK : Notification.TYPE_NEW_SHARED_EVENT) + .withType(oldEvent.type == TYPE_HOMEWORK ? TYPE_NEW_SHARED_HOMEWORK : TYPE_NEW_SHARED_EVENT) .withFragmentRedirect(oldEvent.type == TYPE_HOMEWORK ? MainActivity.DRAWER_ITEM_HOMEWORK : MainActivity.DRAWER_ITEM_AGENDA) .withLongExtra("eventDate", oldEvent.eventDate.getValue()) ); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Notification.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Notification.java index 047cd16f..9a3dc5eb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Notification.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Notification.java @@ -12,6 +12,24 @@ import java.util.Random; import pl.szczodrzynski.edziennik.R; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_AUTO_ARCHIVING; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_ERROR; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_FEEDBACK_MESSAGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_GENERAL; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_LUCKY_NUMBER; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_ANNOUNCEMENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_ATTENDANCE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_EVENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_GRADE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_HOMEWORK; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_MESSAGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_NOTICE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_NEW_SHARED_EVENT; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_SERVER_MESSAGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_TIMETABLE_CHANGED; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_TIMETABLE_LESSON_CHANGE; +import static pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.TYPE_UPDATE; + public class Notification { public int profileId; public String title; @@ -78,25 +96,6 @@ public class Notification { return this; } - public static final int TYPE_GENERAL = 0; - public static final int TYPE_UPDATE = 1; - public static final int TYPE_ERROR = 2; - public static final int TYPE_TIMETABLE_CHANGED = 3; - public static final int TYPE_TIMETABLE_LESSON_CHANGE = 4; - public static final int TYPE_NEW_GRADE = 5; - public static final int TYPE_NEW_EVENT = 6; - public static final int TYPE_NEW_HOMEWORK = 10; - public static final int TYPE_NEW_SHARED_EVENT = 7; - public static final int TYPE_NEW_SHARED_HOMEWORK = 12; - public static final int TYPE_NEW_MESSAGE = 8; - public static final int TYPE_NEW_NOTICE = 9; - public static final int TYPE_NEW_ATTENDANCE = 13; - public static final int TYPE_SERVER_MESSAGE = 11; - public static final int TYPE_LUCKY_NUMBER = 14; - public static final int TYPE_NEW_ANNOUNCEMENT = 15; - public static final int TYPE_FEEDBACK_MESSAGE = 16; - public static final int TYPE_AUTO_ARCHIVING = 17; - public static String stringType(Context context, int errorCode) { switch (errorCode) { diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 82f32af5..bbd86648 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -446,7 +446,8 @@ Absence Excused absence School announcement: %s - %s on lesson %s z %s + %1$s on lesson %2$s on day %3$s + %1$s on day %3$s Late Excused late Notification about data downloading @@ -458,7 +459,8 @@ Notifications about new versions of the app App updates Downloading update… - %s %s from %s + %1$s on %2$s from %3$s + %1$s on %2$s unknown subject Cancel Szkolny.eu: error @@ -469,6 +471,7 @@ Update New grade (%s) from %s Homework from %s for %s + Homework for %s Today %d is the lucky number. The lucky number for %s is %d. The lucky number for tomorrow is %d. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c73422ab..7f43e31a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -487,7 +487,8 @@ Nieobecność Nieobecność usprawiedliwiona Ogłoszenie szkolne: %s - %s na lekcji %s z %s + %1$s na lekcji %2$s z dnia %3$s + %1$s z dnia %3$s Spóźnienie Spóźnienie usprawiedliwione Powiadomienie o pobieraniu danych dla e-dziennika @@ -499,7 +500,8 @@ Powiadomienia o nowych wersjach aplikacji Aktualizacje Pobieranie aktualizacji… - %s %s z %s + %1$s dnia %2$s z %3$s + %1$s dnia %2$s nieznanego przedmiotu Przerwij Szkolny.eu: błąd @@ -509,7 +511,8 @@ Pobieranie danych Synchronizacja Nowa ocena (%s) z %s - Zadanie domowe z %s na %s + Zadanie domowe z %1$s na %2$s + Zadanie domowe na %2$s %s %s - %s Dzisiaj %d to szczęśliwy numerek. Szczęsliwy numerek na %s to %d.