1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-19 22:49:08 -05:00

Migration to WorkManager (#254)

Closes #241
This commit is contained in:
Rafał Borcz 2019-03-09 10:13:36 +01:00 committed by Mikołaj Pich
parent 722f8d691a
commit 919680c766
71 changed files with 889 additions and 807 deletions

View File

@ -19,6 +19,7 @@
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" />
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" />
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
</JetCodeStyleSettings>
<Objective-C-extensions>
<file>

View File

@ -82,7 +82,12 @@ dependencies {
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
implementation "com.firebase:firebase-jobdispatcher:0.8.5"
implementation "android.arch.work:work-rxjava2:1.0.0"
implementation "android.arch.work:work-runtime:1.0.0"
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.2'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.2'
implementation "com.google.dagger:dagger-android-support:2.21"
kapt "com.google.dagger:dagger-compiler:2.21"

View File

@ -42,13 +42,6 @@
android:label="@string/main_title"
android:theme="@style/WulkanowyTheme.NoActionBar" />
<service
android:name=".services.job.SyncWorker"
android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
</intent-filter>
</service>
<service
android:name=".services.widgets.TimetableWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
@ -64,6 +57,12 @@
android:resource="@xml/provider_widget_timetable" />
</receiver>
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />
<meta-data
android:name="io.fabric.ApiKey"
android:value="${fabric_api_key}" />

View File

@ -3,6 +3,8 @@ package io.github.wulkanowy
import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex
import androidx.work.Configuration
import androidx.work.WorkManager
import com.crashlytics.android.Crashlytics
import com.crashlytics.android.core.CrashlyticsCore
import com.jakewharton.threetenabp.AndroidThreeTen
@ -14,6 +16,7 @@ import io.fabric.sdk.android.Fabric
import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.di.DaggerAppComponent
import io.github.wulkanowy.services.sync.SyncWorkerFactory
import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree
import timber.log.Timber
@ -24,6 +27,9 @@ class WulkanowyApp : DaggerApplication() {
@Inject
lateinit var prefRepository: PreferencesRepository
@Inject
lateinit var workerFactory: SyncWorkerFactory
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
@ -35,6 +41,7 @@ class WulkanowyApp : DaggerApplication() {
initializeFabric()
if (DEBUG) enableDebugLog()
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
}
private fun enableDebugLog() {

View File

@ -14,7 +14,7 @@ import javax.inject.Singleton
interface CompletedLessonsDao {
@Insert
fun insertAll(exams: List<CompletedLesson>): List<Long>
fun insertAll(exams: List<CompletedLesson>)
@Delete
fun deleteAll(exams: List<CompletedLesson>)

View File

@ -16,9 +16,6 @@ interface GradeDao {
@Insert
fun insertAll(grades: List<Grade>)
@Update
fun update(grade: Grade)
@Update
fun updateAll(grade: List<Grade>)
@ -28,6 +25,4 @@ interface GradeDao {
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<Grade>>
@Query("SELECT * FROM Grades WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
fun loadAllNew(semesterId: Int, studentId: Int): Maybe<List<Grade>>
}

View File

@ -24,6 +24,6 @@ interface LuckyNumberDao {
fun delete(luckyNumber: LuckyNumber)
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
fun loadFromDate(studentId: Int, date: LocalDate): Maybe<LuckyNumber>
fun load(studentId: Int, date: LocalDate): Maybe<LuckyNumber>
}

View File

@ -12,26 +12,20 @@ import io.reactivex.Maybe
interface MessagesDao {
@Insert
fun insertAll(messages: List<Message>): List<Long>
fun insertAll(messages: List<Message>)
@Delete
fun deleteAll(messages: List<Message>)
@Update
fun update(message: Message)
@Update
fun updateAll(messages: List<Message>)
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND real_id = :id")
fun loadOne(studentId: Int, id: Int): Maybe<Message>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
fun load(studentId: Int, folder: Int): Maybe<List<Message>>
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND real_id = :id")
fun load(studentId: Int, id: Int): Maybe<Message>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
fun loadDeleted(studentId: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE unread = 1 AND student_id = :studentId")
fun loadNewMessages(studentId: Int): Maybe<List<Message>>
}

View File

@ -16,9 +16,6 @@ interface NoteDao {
@Insert
fun insertAll(notes: List<Note>)
@Update
fun update(note: Note)
@Update
fun updateAll(notes: List<Note>)
@ -28,6 +25,4 @@ interface NoteDao {
@Query("SELECT * FROM Notes WHERE student_id = :studentId")
fun loadAll(studentId: Int): Maybe<List<Note>>
@Query("SELECT * FROM Notes WHERE is_read = 0 AND student_id = :studentId")
fun loadNew(studentId: Int): Maybe<List<Note>>
}

View File

@ -25,7 +25,7 @@ data class Note(
var id: Long = 0
@ColumnInfo(name = "is_read")
var isRead: Boolean = false
var isRead: Boolean = true
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true

View File

@ -11,11 +11,6 @@ import javax.inject.Singleton
@Singleton
class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
.filter { !it.isEmpty() }
}
fun saveAttendance(attendance: List<Attendance>) {
attendanceDb.insertAll(attendance)
}
@ -23,4 +18,8 @@ class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDa
fun deleteAttendance(attendance: List<Attendance>) {
attendanceDb.deleteAll(attendance)
}
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate).filter { it.isNotEmpty() }
}
}

View File

@ -10,10 +10,6 @@ import javax.inject.Singleton
@Singleton
class AttendanceSummaryLocal @Inject constructor(private val attendanceDb: AttendanceSummaryDao) {
fun getAttendanceSummary(semester: Semester, subjectId: Int): Maybe<List<AttendanceSummary>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId).filter { !it.isEmpty() }
}
fun saveAttendanceSummary(attendance: List<AttendanceSummary>) {
attendanceDb.insertAll(attendance)
}
@ -21,4 +17,8 @@ class AttendanceSummaryLocal @Inject constructor(private val attendanceDb: Atten
fun deleteAttendanceSummary(attendance: List<AttendanceSummary>) {
attendanceDb.deleteAll(attendance)
}
fun getAttendanceSummary(semester: Semester, subjectId: Int): Maybe<List<AttendanceSummary>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId).filter { it.isNotEmpty() }
}
}

View File

@ -16,7 +16,7 @@ class AttendanceSummaryRepository @Inject constructor(
private val remote: AttendanceSummaryRemote
) {
fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>>? {
fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>> {
return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {

View File

@ -11,10 +11,6 @@ import javax.inject.Singleton
@Singleton
class CompletedLessonsLocal @Inject constructor(private val completedLessonsDb: CompletedLessonsDao) {
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>> {
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end).filter { !it.isEmpty() }
}
fun saveCompletedLessons(completedLessons: List<CompletedLesson>) {
completedLessonsDb.insertAll(completedLessons)
}
@ -22,4 +18,8 @@ class CompletedLessonsLocal @Inject constructor(private val completedLessonsDb:
fun deleteCompleteLessons(completedLessons: List<CompletedLesson>) {
completedLessonsDb.deleteAll(completedLessons)
}
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>> {
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end).filter { it.isNotEmpty() }
}
}

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Completable
import io.reactivex.Maybe
import javax.inject.Inject
import javax.inject.Singleton
@ -11,27 +10,19 @@ import javax.inject.Singleton
@Singleton
class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
fun getGrades(semester: Semester): Maybe<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { !it.isEmpty() }
}
fun getNewGrades(semester: Semester): Maybe<List<Grade>> {
return gradeDb.loadAllNew(semester.semesterId, semester.studentId)
}
fun saveGrades(grades: List<Grade>) {
gradeDb.insertAll(grades)
}
fun updateGrade(grade: Grade): Completable {
return Completable.fromCallable { gradeDb.update(grade) }
}
fun updateGrades(grades: List<Grade>): Completable {
return Completable.fromCallable { gradeDb.updateAll(grades) }
}
fun deleteGrades(grades: List<Grade>) {
gradeDb.deleteAll(grades)
}
fun updateGrades(grades: List<Grade>) {
gradeDb.updateAll(grades)
}
fun getGrades(semester: Semester): Maybe<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
}
}

View File

@ -31,24 +31,28 @@ class GradeRepository @Inject constructor(
local.deleteGrades(oldGrades - newGrades)
local.saveGrades((newGrades - oldGrades)
.onEach {
if (it.date >= notifyBreakDate) {
if (notify) it.isNotified = false
it.isRead = false
if (it.date >= notifyBreakDate) it.apply {
isRead = false
if (notify) isNotified = false
}
})
}
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
}
fun getNewGrades(semester: Semester): Single<List<Grade>> {
return local.getNewGrades(semester).toSingle(emptyList())
fun getUnreadGrades(semester: Semester): Single<List<Grade>> {
return local.getGrades(semester).map { it.filter { grade -> !grade.isRead } }.toSingle(emptyList())
}
fun getNotNotifiedGrades(semester: Semester): Single<List<Grade>> {
return local.getGrades(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList())
}
fun updateGrade(grade: Grade): Completable {
return local.updateGrade(grade)
return Completable.fromCallable { local.updateGrades(listOf(grade)) }
}
fun updateGrades(grades: List<Grade>): Completable {
return local.updateGrades(grades)
return Completable.fromCallable { local.updateGrades(grades) }
}
}

View File

@ -10,11 +10,6 @@ import javax.inject.Singleton
@Singleton
class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSummaryDao) {
fun getGradesSummary(semester: Semester): Maybe<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
.filter { !it.isEmpty() }
}
fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.insertAll(gradesSummary)
}
@ -22,4 +17,8 @@ class GradeSummaryLocal @Inject constructor(private val gradeSummaryDb: GradeSum
fun deleteGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.deleteAll(gradesSummary)
}
fun getGradesSummary(semester: Semester): Maybe<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
}
}

View File

@ -11,10 +11,6 @@ import javax.inject.Singleton
@Singleton
class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
fun getHomework(semester: Semester, date: LocalDate): Maybe<List<Homework>> {
return homeworkDb.loadAll(semester.semesterId, semester.studentId, date).filter { !it.isEmpty() }
}
fun saveHomework(homework: List<Homework>) {
homeworkDb.insertAll(homework)
}
@ -22,4 +18,8 @@ class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) {
fun deleteHomework(homework: List<Homework>) {
homeworkDb.deleteAll(homework)
}
fun getHomework(semester: Semester, date: LocalDate): Maybe<List<Homework>> {
return homeworkDb.loadAll(semester.semesterId, semester.studentId, date).filter { it.isNotEmpty() }
}
}

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.repositories.luckynumber
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Completable
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import javax.inject.Inject
@ -12,19 +11,19 @@ import javax.inject.Singleton
@Singleton
class LuckyNumberLocal @Inject constructor(private val luckyNumberDb: LuckyNumberDao) {
fun getLuckyNumber(semester: Semester, date: LocalDate): Maybe<LuckyNumber> {
return luckyNumberDb.loadFromDate(semester.studentId, date)
}
fun saveLuckyNumber(luckyNumber: LuckyNumber) {
luckyNumberDb.insert(luckyNumber)
}
fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable {
return Completable.fromCallable { luckyNumberDb.update(luckyNumber) }
fun updateLuckyNumber(luckyNumber: LuckyNumber) {
luckyNumberDb.update(luckyNumber)
}
fun deleteLuckyNumber(luckyNumber: LuckyNumber) {
luckyNumberDb.delete(luckyNumber)
}
fun getLuckyNumber(semester: Semester, date: LocalDate): Maybe<LuckyNumber> {
return luckyNumberDb.load(semester.studentId, date)
}
}

View File

@ -44,7 +44,11 @@ class LuckyNumberRepository @Inject constructor(
)
}
fun getNotNotifiedLuckyNumber(semester: Semester): Maybe<LuckyNumber> {
return local.getLuckyNumber(semester, LocalDate.now()).filter { !it.isNotified }
}
fun updateLuckyNumber(luckyNumber: LuckyNumber): Completable {
return local.updateLuckyNumber(luckyNumber)
return Completable.fromCallable { local.updateLuckyNumber(luckyNumber) }
}
}

View File

@ -0,0 +1,7 @@
package io.github.wulkanowy.data.repositories.message
enum class MessageFolder(val id: Int = 1) {
RECEIVED(1),
SENT(2),
TRASHED(3)
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.message
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
import io.reactivex.Maybe
import javax.inject.Inject
import javax.inject.Singleton
@ -10,34 +11,26 @@ import javax.inject.Singleton
@Singleton
class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
fun getMessage(studentId: Int, id: Int): Maybe<Message> {
return messagesDb.loadOne(studentId, id)
}
fun getMessages(studentId: Int, folder: MessageRepository.MessageFolder): Maybe<List<Message>> {
return when (folder) {
MessageRepository.MessageFolder.TRASHED -> messagesDb.loadDeleted(studentId)
else -> messagesDb.load(studentId, folder.id)
}.filter { !it.isEmpty() }
}
fun getNewMessages(student: Student): Maybe<List<Message>> {
return messagesDb.loadNewMessages(student.studentId)
}
fun saveMessages(messages: List<Message>): List<Long> {
return messagesDb.insertAll(messages)
}
fun updateMessage(message: Message) {
return messagesDb.update(message)
fun saveMessages(messages: List<Message>) {
messagesDb.insertAll(messages)
}
fun updateMessages(messages: List<Message>) {
return messagesDb.updateAll(messages)
messagesDb.updateAll(messages)
}
fun deleteMessages(messages: List<Message>) {
messagesDb.deleteAll(messages)
}
fun getMessage(student: Student, id: Int): Maybe<Message> {
return messagesDb.load(student.studentId, id)
}
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
return when (folder) {
TRASHED -> messagesDb.loadDeleted(student.studentId)
else -> messagesDb.loadAll(student.studentId, folder.id)
}.filter { it.isNotEmpty() }
}
}

View File

@ -16,7 +16,7 @@ import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
@Singleton
class MessageRemote @Inject constructor(private val api: Api) {
fun getMessages(studentId: Int, folder: MessageRepository.MessageFolder): Single<List<Message>> {
fun getMessages(studentId: Int, folder: MessageFolder): Single<List<Message>> {
return api.getMessages(Folder.valueOf(folder.name)).map { messages ->
messages.map {
Message(

View File

@ -7,6 +7,7 @@ import io.github.wulkanowy.data.ApiHelper
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
import io.reactivex.Completable
import io.reactivex.Single
import java.net.UnknownHostException
@ -21,22 +22,16 @@ class MessageRepository @Inject constructor(
private val apiHelper: ApiHelper
) {
enum class MessageFolder(val id: Int = 1) {
RECEIVED(1),
SENT(2),
TRASHED(3)
}
fun getMessages(student: Student, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Message>> {
return Single.just(apiHelper.initApi(student))
.flatMap { _ ->
local.getMessages(student.studentId, folder).filter { !forceRefresh }
local.getMessages(student, folder).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getMessages(student.studentId, folder)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getMessages(student.studentId, folder).toSingle(emptyList())
local.getMessages(student, folder).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteMessages(old - new)
local.saveMessages((new - old)
@ -44,7 +39,7 @@ class MessageRepository @Inject constructor(
it.isNotified = !notify
})
}
}.flatMap { local.getMessages(student.studentId, folder).toSingle(emptyList()) }
}.flatMap { local.getMessages(student, folder).toSingle(emptyList()) }
)
}
}
@ -52,33 +47,35 @@ class MessageRepository @Inject constructor(
fun getMessage(student: Student, messageId: Int, markAsRead: Boolean = false): Single<Message> {
return Single.just(apiHelper.initApi(student))
.flatMap { _ ->
local.getMessage(student.studentId, messageId)
local.getMessage(student, messageId)
.filter { !it.content.isNullOrEmpty() }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) local.getMessage(student.studentId, messageId).toSingle()
if (it) local.getMessage(student, messageId).toSingle()
else Single.error(UnknownHostException())
}
.flatMap { dbMessage ->
remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
local.updateMessage(dbMessage.copy(unread = false).apply {
local.updateMessages(listOf(dbMessage.copy(unread = false).apply {
id = dbMessage.id
content = it
})
}))
}
}.flatMap {
local.getMessage(student.studentId, messageId).toSingle()
local.getMessage(student, messageId).toSingle()
}
)
}
}
fun getNewMessages(student: Student): Single<List<Message>> {
return local.getNewMessages(student).toSingle(emptyList())
fun getNotNotifiedMessages(student: Student): Single<List<Message>> {
return local.getMessages(student, RECEIVED)
.map { it.filter { message -> !message.isNotified && message.unread } }
.toSingle(emptyList())
}
fun updateMessage(message: Message): Completable {
return Completable.fromCallable { local.updateMessage(message) }
return Completable.fromCallable { local.updateMessages(listOf(message)) }
}
fun updateMessages(messages: List<Message>): Completable {

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.repositories.note
import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Completable
import io.reactivex.Maybe
import javax.inject.Inject
import javax.inject.Singleton
@ -11,27 +10,19 @@ import javax.inject.Singleton
@Singleton
class NoteLocal @Inject constructor(private val noteDb: NoteDao) {
fun getNotes(student: Student): Maybe<List<Note>> {
return noteDb.loadAll(student.studentId).filter { !it.isEmpty() }
}
fun getNewNotes(student: Student): Maybe<List<Note>> {
return noteDb.loadNew(student.studentId)
}
fun saveNotes(notes: List<Note>) {
noteDb.insertAll(notes)
}
fun updateNote(note: Note): Completable {
return Completable.fromCallable { noteDb.update(note) }
}
fun updateNotes(notes: List<Note>): Completable {
return Completable.fromCallable { noteDb.updateAll(notes) }
fun updateNotes(notes: List<Note>) {
noteDb.updateAll(notes)
}
fun deleteNotes(notes: List<Note>) {
noteDb.deleteAll(notes)
}
fun getNotes(student: Student): Maybe<List<Note>> {
return noteDb.loadAll(student.studentId).filter { it.isNotEmpty() }
}
}

View File

@ -30,24 +30,24 @@ class NoteRepository @Inject constructor(
local.deleteNotes(old - new)
local.saveNotes((new - old)
.onEach {
if (student.registrationDate <= it.date.atStartOfDay()) {
if (notify) it.isNotified = false
it.isRead = false
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
isRead = false
if (notify) isNotified = false
}
})
}
}.flatMap { local.getNotes(student).toSingle(emptyList()) })
}
fun getNewNotes(student: Student): Single<List<Note>> {
return local.getNewNotes(student).toSingle(emptyList())
fun getNotNotifiedNotes(student: Student): Single<List<Note>> {
return local.getNotes(student).map { it.filter { note -> !note.isNotified } }.toSingle(emptyList())
}
fun updateNote(note: Note): Completable {
return local.updateNote(note)
return Completable.fromCallable { local.updateNotes(listOf(note)) }
}
fun updateNotes(notes: List<Note>): Completable {
return local.updateNotes(notes)
return Completable.fromCallable { local.updateNotes(notes) }
}
}

View File

@ -12,7 +12,7 @@ class PreferencesRepository @Inject constructor(
val context: Context
) {
val startMenuIndex: Int
get() = sharedPref.getString(context.getString(R.string.pref_key_start_menu), "0")?.toInt() ?: 0
get() = sharedPref.getString(context.getString(R.string.pref_key_start_menu), "0")?.toIntOrNull() ?: 0
val isShowPresent: Boolean
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
@ -22,25 +22,24 @@ class PreferencesRepository @Inject constructor(
val currentThemeKey: String = context.getString(R.string.pref_key_theme)
val currentTheme: Int
get() = sharedPref.getString(currentThemeKey, "1")?.toInt() ?: 1
get() = sharedPref.getString(currentThemeKey, "1")?.toIntOrNull() ?: 1
val gradePlusModifier: Double
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDoubleOrNull() ?: 0.0
val gradeMinusModifier: Double
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble() ?: 0.0
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDoubleOrNull() ?: 0.0
val gradeColorTheme: String
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_color_scheme), "vulcan") ?: "vulcan"
val serviceEnablesKey: String = context.getString(R.string.pref_key_services_enable)
val serviceEnableKey: String = context.getString(R.string.pref_key_services_enable)
val isServiceEnabled: Boolean
get() = sharedPref.getBoolean(serviceEnablesKey, true)
get() = sharedPref.getBoolean(serviceEnableKey, true)
val servicesIntervalKey: String = context.getString(R.string.pref_key_services_interval)
val servicesInterval: Int
get() = sharedPref.getString(servicesIntervalKey, "60")?.toInt() ?: 60
val servicesInterval: Long
get() = sharedPref.getString(servicesIntervalKey, "60")?.toLongOrNull() ?: 60
val servicesOnlyWifiKey: String = context.getString(R.string.pref_key_services_wifi_only)
val isServicesOnlyWifi: Boolean

View File

@ -11,11 +11,6 @@ import javax.inject.Singleton
@Singleton
class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao) {
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Timetable>> {
return timetableDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
.filter { !it.isEmpty() }
}
fun saveTimetable(timetables: List<Timetable>) {
timetableDb.insertAll(timetables)
}
@ -23,4 +18,8 @@ class TimetableLocal @Inject constructor(private val timetableDb: TimetableDao)
fun deleteTimetable(timetables: List<Timetable>) {
timetableDb.deleteAll(timetables)
}
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Timetable>> {
return timetableDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate).filter { it.isNotEmpty() }
}
}

View File

@ -5,6 +5,7 @@ import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule
import io.github.wulkanowy.WulkanowyApp
import io.github.wulkanowy.data.RepositoryModule
import io.github.wulkanowy.services.ServicesModule
import javax.inject.Singleton
@Singleton
@ -12,6 +13,7 @@ import javax.inject.Singleton
AndroidSupportInjectionModule::class,
AppModule::class,
RepositoryModule::class,
ServicesModule::class,
BuilderModule::class])
interface AppComponent : AndroidInjector<WulkanowyApp> {

View File

@ -2,8 +2,6 @@ package io.github.wulkanowy.di
import android.appwidget.AppWidgetManager
import android.content.Context
import com.firebase.jobdispatcher.FirebaseJobDispatcher
import com.firebase.jobdispatcher.GooglePlayDriver
import com.google.firebase.analytics.FirebaseAnalytics
import dagger.Module
import dagger.Provides
@ -30,10 +28,6 @@ internal class AppModule {
@Provides
fun provideFlexibleAdapter() = FlexibleAdapter<AbstractFlexibleItem<*>>(null, null, true)
@Singleton
@Provides
fun provideJobDispatcher(context: Context) = FirebaseJobDispatcher(GooglePlayDriver(context))
@Singleton
@Provides
fun provideFirebaseAnalyticsHelper(context: Context) = FirebaseAnalyticsHelper(FirebaseAnalytics.getInstance(context))

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.di
import dagger.Module
import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.services.job.SyncWorker
import io.github.wulkanowy.services.widgets.TimetableWidgetService
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginModule
@ -32,7 +31,4 @@ internal abstract class BuilderModule {
@ContributesAndroidInjector
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
@ContributesAndroidInjector
abstract fun bindSyncJob(): SyncWorker
}

View File

@ -0,0 +1,102 @@
package io.github.wulkanowy.services
import android.app.NotificationManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import androidx.core.app.NotificationManagerCompat
import androidx.work.WorkManager
import com.squareup.inject.assisted.dagger2.AssistedModule
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
import io.github.wulkanowy.services.sync.works.AttendanceWork
import io.github.wulkanowy.services.sync.works.CompletedLessonWork
import io.github.wulkanowy.services.sync.works.ExamWork
import io.github.wulkanowy.services.sync.works.GradeStatisticsWork
import io.github.wulkanowy.services.sync.works.GradeSummaryWork
import io.github.wulkanowy.services.sync.works.GradeWork
import io.github.wulkanowy.services.sync.works.HomeworkWork
import io.github.wulkanowy.services.sync.works.LuckyNumberWork
import io.github.wulkanowy.services.sync.works.MessageWork
import io.github.wulkanowy.services.sync.works.NoteWork
import io.github.wulkanowy.services.sync.works.RecipientWork
import io.github.wulkanowy.services.sync.works.TimetableWork
import io.github.wulkanowy.services.sync.works.Work
import javax.inject.Singleton
@AssistedModule
@Module(includes = [AssistedInject_ServicesModule::class])
abstract class ServicesModule {
@Module
companion object {
@JvmStatic
@Provides
fun provideWorkManager() = WorkManager.getInstance()
@JvmStatic
@Singleton
@Provides
fun provideNotificationManagerCompat(context: Context) = NotificationManagerCompat.from(context)
@JvmStatic
@Singleton
@Provides
fun provideNotificationManager(context: Context) = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
}
@Binds
@IntoSet
abstract fun provideGradeWork(work: GradeWork): Work
@Binds
@IntoSet
abstract fun provideNoteWork(work: NoteWork): Work
@Binds
@IntoSet
abstract fun provideAttendanceWork(work: AttendanceWork): Work
@Binds
@IntoSet
abstract fun provideGradeSummaryWork(work: GradeSummaryWork): Work
@Binds
@IntoSet
abstract fun provideExamWork(work: ExamWork): Work
@Binds
@IntoSet
abstract fun provideAttendanceSummaryWork(work: AttendanceSummaryWork): Work
@Binds
@IntoSet
abstract fun provideTimetableWork(work: TimetableWork): Work
@Binds
@IntoSet
abstract fun provideLuckyNumberWork(work: LuckyNumberWork): Work
@Binds
@IntoSet
abstract fun provideCompletedLessonWork(work: CompletedLessonWork): Work
@Binds
@IntoSet
abstract fun provideHomeworkWork(work: HomeworkWork): Work
@Binds
@IntoSet
abstract fun provideMessageWork(work: MessageWork): Work
@Binds
@IntoSet
abstract fun provideRecipientWork(work: RecipientWork): Work
@Binds
@IntoSet
abstract fun provideGradeStatistics(work: GradeStatisticsWork): Work
}

View File

@ -1,57 +0,0 @@
package io.github.wulkanowy.services.job
import com.firebase.jobdispatcher.Constraint.ON_ANY_NETWORK
import com.firebase.jobdispatcher.Constraint.ON_UNMETERED_NETWORK
import com.firebase.jobdispatcher.FirebaseJobDispatcher
import com.firebase.jobdispatcher.Lifetime.FOREVER
import com.firebase.jobdispatcher.RetryStrategy.DEFAULT_EXPONENTIAL
import com.firebase.jobdispatcher.Trigger.executionWindow
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.utils.isHolidays
import org.threeten.bp.LocalDate
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ServiceHelper @Inject constructor(
private val prefRepository: PreferencesRepository,
private val dispatcher: FirebaseJobDispatcher
) {
fun reloadFullSyncService() {
startFullSyncService(true)
}
fun startFullSyncService(replaceCurrent: Boolean = false) {
if (LocalDate.now().isHolidays || !prefRepository.isServiceEnabled) {
Timber.d("Services disabled or it's holidays")
return
}
dispatcher.mustSchedule(
dispatcher.newJobBuilder()
.setLifetime(FOREVER)
.setRecurring(true)
.setService(SyncWorker::class.java)
.setTag(SyncWorker.WORK_TAG)
.setTrigger(
executionWindow(
prefRepository.servicesInterval * 60,
(prefRepository.servicesInterval + 10) * 60
)
)
.setConstraints(if (prefRepository.isServicesOnlyWifi) ON_UNMETERED_NETWORK else ON_ANY_NETWORK)
.setReplaceCurrent(replaceCurrent)
.setRetryStrategy(DEFAULT_EXPONENTIAL)
.build()
)
Timber.d("Services started")
}
fun stopFullSyncService() {
dispatcher.cancel(SyncWorker.WORK_TAG)
Timber.d("Services stopped")
}
}

View File

@ -1,214 +0,0 @@
package io.github.wulkanowy.services.job
import com.firebase.jobdispatcher.JobParameters
import com.firebase.jobdispatcher.SimpleJobService
import dagger.android.AndroidInjection
import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRepository
import io.github.wulkanowy.data.repositories.exam.ExamRepository
import io.github.wulkanowy.data.repositories.grade.GradeRepository
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
import io.github.wulkanowy.data.repositories.message.MessageRepository
import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.note.NoteRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.recipient.RecipientRepository
import io.github.wulkanowy.data.repositories.reportingunit.ReportingUnitRepository
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
import io.github.wulkanowy.services.notification.GradeNotification
import io.github.wulkanowy.services.notification.LuckyNumberNotification
import io.github.wulkanowy.services.notification.MessageNotification
import io.github.wulkanowy.services.notification.NoteNotification
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.isHolidays
import io.github.wulkanowy.utils.monday
import io.reactivex.Completable
import io.reactivex.Maybe
import io.reactivex.Single
import io.reactivex.disposables.CompositeDisposable
import org.threeten.bp.LocalDate
import timber.log.Timber
import javax.inject.Inject
class SyncWorker : SimpleJobService() {
@Inject
lateinit var student: StudentRepository
@Inject
lateinit var semester: SemesterRepository
@Inject
lateinit var gradesDetails: GradeRepository
@Inject
lateinit var gradesSummary: GradeSummaryRepository
@Inject
lateinit var attendance: AttendanceRepository
@Inject
lateinit var exam: ExamRepository
@Inject
lateinit var timetable: TimetableRepository
@Inject
lateinit var message: MessageRepository
@Inject
lateinit var note: NoteRepository
@Inject
lateinit var homework: HomeworkRepository
@Inject
lateinit var luckyNumber: LuckyNumberRepository
@Inject
lateinit var completedLessons: CompletedLessonsRepository
@Inject
lateinit var reportingUnitRepository: ReportingUnitRepository
@Inject
lateinit var recipientRepository: RecipientRepository
@Inject
lateinit var prefRepository: PreferencesRepository
private val disposable = CompositeDisposable()
companion object {
const val WORK_TAG = "FULL_SYNC"
}
override fun onCreate() {
super.onCreate()
AndroidInjection.inject(this)
}
override fun onRunJob(job: JobParameters?): Int {
Timber.d("Synchronization started")
val start = LocalDate.now().monday
val end = LocalDate.now().friday
if (start.isHolidays) return RESULT_FAIL_NORETRY
var error: Throwable? = null
val notify = prefRepository.isNotificationsEnable
disposable.add(student.isStudentSaved()
.flatMapMaybe { if (it) student.getCurrentStudent().toMaybe() else Maybe.empty() }
.flatMap { semester.getCurrentSemester(it, true).map { semester -> semester to it }.toMaybe() }
.flatMapCompletable { c ->
Completable.merge(
listOf(
gradesDetails.getGrades(c.second, c.first, true, notify).ignoreElement(),
gradesSummary.getGradesSummary(c.first, true).ignoreElement(),
attendance.getAttendance(c.first, start, end, true).ignoreElement(),
exam.getExams(c.first, start, end, true).ignoreElement(),
timetable.getTimetable(c.first, start, end, true).ignoreElement(),
message.getMessages(c.second, RECEIVED, true, notify).ignoreElement(),
note.getNotes(c.second, c.first, true, notify).ignoreElement(),
homework.getHomework(c.first, LocalDate.now(), true).ignoreElement(),
homework.getHomework(c.first, LocalDate.now().plusDays(1), true).ignoreElement(),
luckyNumber.getLuckyNumber(c.first, true, notify).ignoreElement(),
completedLessons.getCompletedLessons(c.first, start, end, true).ignoreElement()
) + reportingUnitRepository.getReportingUnits(c.second, true)
.flatMapPublisher { reportingUnits ->
Single.merge(reportingUnits.map { recipientRepository.getRecipients(c.second, 2, it, true) })
}.ignoreElements()
)
}
.subscribe({}, { error = it }))
return if (null === error) {
if (notify) sendNotifications()
Timber.d("Synchronization successful")
RESULT_SUCCESS
} else {
Timber.e(error, "Synchronization failed")
RESULT_FAIL_RETRY
}
}
private fun sendNotifications() {
sendGradeNotifications()
sendMessageNotification()
sendNoteNotification()
sendLuckyNumberNotification()
}
private fun sendGradeNotifications() {
disposable.add(student.getCurrentStudent()
.flatMap { semester.getCurrentSemester(it) }
.flatMap { gradesDetails.getNewGrades(it) }
.map { it.filter { grade -> !grade.isNotified } }
.doOnSuccess {
if (it.isNotEmpty()) {
Timber.d("Found ${it.size} unread grades")
GradeNotification(applicationContext).sendNotification(it)
}
}
.map { it.map { grade -> grade.apply { isNotified = true } } }
.flatMapCompletable { gradesDetails.updateGrades(it) }
.subscribe({}, { Timber.e(it, "Grade notifications sending failed") }))
}
private fun sendMessageNotification() {
disposable.add(student.getCurrentStudent()
.flatMap { message.getNewMessages(it) }
.map { it.filter { message -> !message.isNotified } }
.doOnSuccess {
if (it.isNotEmpty()) {
Timber.d("Found ${it.size} unread messages")
MessageNotification(applicationContext).sendNotification(it)
}
}
.map { it.map { message -> message.apply { isNotified = true } } }
.flatMapCompletable { message.updateMessages(it) }
.subscribe({}, { Timber.e(it, "Message notifications sending failed") })
)
}
private fun sendNoteNotification() {
disposable.add(student.getCurrentStudent()
.flatMap { note.getNewNotes(it) }
.map { it.filter { note -> !note.isNotified } }
.doOnSuccess {
if (it.isNotEmpty()) {
Timber.d("Found ${it.size} unread notes")
NoteNotification(applicationContext).sendNotification(it)
}
}
.map { it.map { note -> note.apply { isNotified = true } } }
.flatMapCompletable { note.updateNotes(it) }
.subscribe({}, { Timber.e("Notifications sending failed") })
)
}
private fun sendLuckyNumberNotification() {
disposable.add(student.getCurrentStudent()
.flatMap { semester.getCurrentSemester(it) }
.flatMapMaybe { luckyNumber.getLuckyNumber(it) }
.filter { !it.isNotified }
.doOnSuccess {
LuckyNumberNotification(applicationContext).sendNotification(it)
}
.map { it.apply { isNotified = true } }
.flatMapCompletable { luckyNumber.updateLuckyNumber(it) }
.subscribe({}, { Timber.e("Lucky number notification sending failed") }))
}
override fun onDestroy() {
super.onDestroy()
disposable.clear()
}
}

View File

@ -1,34 +0,0 @@
package io.github.wulkanowy.services.notification
import android.app.Notification
import android.app.NotificationManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.O
import androidx.core.app.NotificationCompat
import timber.log.Timber
import kotlin.random.Random
abstract class BaseNotification(protected val context: Context) {
protected val notificationManager: NotificationManager by lazy {
context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
}
fun notify(notification: Notification) {
notificationManager.notify(Random.nextInt(1000), notification)
}
fun notificationBuilder(channelId: String): NotificationCompat.Builder {
if (SDK_INT >= O) createChannel(channelId)
return NotificationCompat.Builder(context, channelId)
}
fun cancelAll() {
notificationManager.cancelAll()
Timber.d("Notifications canceled")
}
abstract fun createChannel(channelId: String)
}

View File

@ -1,60 +0,0 @@
package io.github.wulkanowy.services.notification
import android.annotation.TargetApi
import android.app.Notification.VISIBILITY_PUBLIC
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
import timber.log.Timber
class GradeNotification(context: Context) : BaseNotification(context) {
private val channelId = "Grade_Notify"
@TargetApi(26)
override fun createChannel(channelId: String) {
notificationManager.createNotificationChannel(NotificationChannel(
channelId, context.getString(R.string.notify_grade_channel), IMPORTANCE_HIGH
).apply {
enableLights(true)
enableVibration(true)
lockscreenVisibility = VISIBILITY_PUBLIC
})
}
fun sendNotification(items: List<Grade>) {
notify(notificationBuilder(channelId)
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, items.size, items.size))
.setContentText(context.resources.getQuantityString(R.plurals.notify_grade_new_items, items.size, items.size))
.setSmallIcon(R.drawable.ic_stat_notify_grade)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 0),
FLAG_UPDATE_CURRENT
)
)
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, items.size, items.size))
items.forEach {
addLine("${it.subject}: ${it.entry}")
}
this
})
.build()
)
Timber.d("Notification sent")
}
}

View File

@ -1,48 +0,0 @@
package io.github.wulkanowy.services.notification
import android.annotation.TargetApi
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.ui.modules.main.MainActivity
class LuckyNumberNotification(context: Context) : BaseNotification(context) {
private val channelId = "Lucky_Number_Notify"
@TargetApi(26)
override fun createChannel(channelId: String) {
notificationManager.createNotificationChannel(NotificationChannel(
channelId, context.getString(R.string.notify_lucky_number_channel), NotificationManager.IMPORTANCE_HIGH
).apply {
enableLights(true)
enableVibration(true)
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
})
}
fun sendNotification(luckyNumber: LuckyNumber) {
notify(notificationBuilder(channelId)
.setContentTitle(context.getString(R.string.notify_lucky_number_new_item_title))
.setContentText(context.getString(R.string.notify_lucky_number_new_item, luckyNumber.luckyNumber))
.setSmallIcon(R.drawable.ic_stat_notify_lucky_number)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4),
PendingIntent.FLAG_UPDATE_CURRENT
)
)
.build()
)
}
}

View File

@ -1,58 +0,0 @@
package io.github.wulkanowy.services.notification
import android.annotation.TargetApi
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.ui.modules.main.MainActivity
import timber.log.Timber
class MessageNotification(context: Context) : BaseNotification(context) {
private val channelId = "Message_Notify"
@TargetApi(26)
override fun createChannel(channelId: String) {
notificationManager.createNotificationChannel(NotificationChannel(
channelId, context.getString(R.string.notify_message_channel), NotificationManager.IMPORTANCE_HIGH
).apply {
enableLights(true)
enableVibration(true)
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
})
}
fun sendNotification(items: List<Message>) {
notify(notificationBuilder(channelId)
.setContentTitle(context.resources.getQuantityString(R.plurals.message_new_items, items.size, items.size))
.setContentText(context.resources.getQuantityString(R.plurals.notify_message_new_items, items.size, items.size))
.setSmallIcon(R.drawable.ic_stat_notify_message)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4),
PendingIntent.FLAG_UPDATE_CURRENT
)
)
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, items.size, items.size))
items.forEach {
addLine("${it.sender}: ${it.subject}")
}
this
})
.build()
)
Timber.d("Notification sent")
}
}

View File

@ -1,58 +0,0 @@
package io.github.wulkanowy.services.notification
import android.annotation.TargetApi
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.ui.modules.main.MainActivity
import timber.log.Timber
class NoteNotification(context: Context) : BaseNotification(context) {
private val channelId = "Note_Notify"
@TargetApi(26)
override fun createChannel(channelId: String) {
notificationManager.createNotificationChannel(NotificationChannel(
channelId, context.getString(R.string.notify_note_channel), NotificationManager.IMPORTANCE_HIGH
).apply {
enableLights(true)
enableVibration(true)
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
})
}
fun sendNotification(items: List<Note>) {
notify(notificationBuilder(channelId)
.setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, items.size, items.size))
.setContentText(context.resources.getQuantityString(R.plurals.notify_note_new_items, items.size, items.size))
.setSmallIcon(R.drawable.ic_stat_notify_note)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(MainActivity.EXTRA_START_MENU_INDEX, 4),
PendingIntent.FLAG_UPDATE_CURRENT
)
)
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, items.size, items.size))
items.forEach {
addLine("${it.teacher}: ${it.category}")
}
this
})
.build()
)
Timber.d("Notification sent")
}
}

View File

@ -0,0 +1,50 @@
package io.github.wulkanowy.services.sync
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.O
import androidx.work.BackoffPolicy.EXPONENTIAL
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
import androidx.work.NetworkType.METERED
import androidx.work.NetworkType.UNMETERED
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
import io.github.wulkanowy.utils.isHolidays
import org.threeten.bp.LocalDate.now
import timber.log.Timber
import java.util.concurrent.TimeUnit.MINUTES
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SyncManager @Inject constructor(
private val workManager: WorkManager,
private val preferencesRepository: PreferencesRepository,
newEntriesChannel: NewEntriesChannel
) {
init {
if (SDK_INT >= O) newEntriesChannel.create()
if (now().isHolidays) stopSyncWorker()
Timber.i("SyncManager was initialized")
}
fun startSyncWorker(restart: Boolean = false) {
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
PeriodicWorkRequest.Builder(SyncWorker::class.java, preferencesRepository.servicesInterval, MINUTES, 10, MINUTES)
.setBackoffCriteria(EXPONENTIAL, 30, MINUTES)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(if (preferencesRepository.isServicesOnlyWifi) METERED else UNMETERED)
.build())
.build())
}
}
fun stopSyncWorker() {
workManager.cancelUniqueWork(SyncWorker::class.java.simpleName)
}
}

View File

@ -0,0 +1,45 @@
package io.github.wulkanowy.services.sync
import android.content.Context
import androidx.work.ListenableWorker
import androidx.work.RxWorker
import androidx.work.WorkerParameters
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.services.sync.works.Work
import io.reactivex.Completable
import io.reactivex.Single
import timber.log.Timber
class SyncWorker @AssistedInject constructor(
@Assisted appContext: Context,
@Assisted workerParameters: WorkerParameters,
private val studentRepository: StudentRepository,
private val semesterRepository: SemesterRepository,
private val works: Set<@JvmSuppressWildcards Work>
) : RxWorker(appContext, workerParameters) {
override fun createWork(): Single<Result> {
return studentRepository.getCurrentStudent()
.flatMapCompletable { student ->
semesterRepository.getCurrentSemester(student, true)
.flatMapCompletable { semester ->
Completable.mergeDelayError(works.map { it.create(student, semester) })
}
}
.toSingleDefault(Result.success())
.onErrorReturn {
Timber.e(it, "There was an error during synchronization")
Result.retry()
}
}
@AssistedInject.Factory
interface Factory {
fun create(appContext: Context, workerParameters: WorkerParameters): ListenableWorker
}
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.services.sync
import android.content.Context
import androidx.work.ListenableWorker
import androidx.work.WorkerFactory
import androidx.work.WorkerParameters
import timber.log.Timber
import javax.inject.Inject
class SyncWorkerFactory @Inject constructor(private val syncWorkerFactory: SyncWorker.Factory) : WorkerFactory() {
override fun createWorker(appContext: Context, workerClassName: String, workerParameters: WorkerParameters): ListenableWorker? {
return if (workerClassName == SyncWorker::class.java.name) {
syncWorkerFactory.create(appContext, workerParameters)
} else {
Timber.e(IllegalArgumentException("Unknown worker class name: $workerClassName"))
null
}
}
}

View File

@ -0,0 +1,30 @@
package io.github.wulkanowy.services.sync.channels
import android.annotation.TargetApi
import android.app.Notification.VISIBILITY_PUBLIC
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.content.Context
import io.github.wulkanowy.R
import javax.inject.Inject
@TargetApi(26)
class NewEntriesChannel @Inject constructor(
private val notificationManager: NotificationManager,
private val context: Context
) {
companion object {
const val CHANNEL_ID = "new_entries_channel"
}
fun create() {
notificationManager.createNotificationChannel(
NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_new_entries), IMPORTANCE_HIGH).apply {
enableLights(true)
enableVibration(true)
lockscreenVisibility = VISIBILITY_PUBLIC
})
}
}

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.attendancesummary.AttendanceSummaryRepository
import io.reactivex.Completable
import javax.inject.Inject
class AttendanceSummaryWork @Inject constructor(
private val attendanceSummaryRepository: AttendanceSummaryRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return attendanceSummaryRepository.getAttendanceSummary(semester, -1, true).ignoreElement()
}
}

View File

@ -0,0 +1,18 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.attendance.AttendanceRepository
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Completable
import org.threeten.bp.LocalDate.now
import javax.inject.Inject
class AttendanceWork @Inject constructor(private val attendanceRepository: AttendanceRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return attendanceRepository.getAttendance(semester, now().monday, now().friday, true)
.ignoreElement()
}
}

View File

@ -0,0 +1,21 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRepository
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Completable
import org.threeten.bp.LocalDate.now
import javax.inject.Inject
class CompletedLessonWork @Inject constructor(
private val completedLessonsRepository: CompletedLessonsRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return completedLessonsRepository.getCompletedLessons(semester, now().monday, now().friday, true)
.ignoreElement()
}
}

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.exam.ExamRepository
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Completable
import org.threeten.bp.LocalDate.now
import javax.inject.Inject
class ExamWork @Inject constructor(private val examRepository: ExamRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return examRepository.getExams(semester, now().monday, now().friday, true).ignoreElement()
}
}

View File

@ -0,0 +1,16 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.gradestatistics.GradeStatisticsRepository
import io.reactivex.Completable
import javax.inject.Inject
class GradeStatisticsWork @Inject constructor(private val gradeStatisticsRepository: GradeStatisticsRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return gradeStatisticsRepository.getGradesStatistics(semester, "Wszystkie", false, true)
.ignoreElement()
}
}

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
import io.reactivex.Completable
import javax.inject.Inject
class GradeSummaryWork @Inject constructor(private val gradeSummaryRepository: GradeSummaryRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return gradeSummaryRepository.getGradesSummary(semester, true).ignoreElement()
}
}

View File

@ -0,0 +1,61 @@
package io.github.wulkanowy.services.sync.works
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.DEFAULT_ALL
import androidx.core.app.NotificationCompat.PRIORITY_HIGH
import androidx.core.app.NotificationManagerCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.grade.GradeRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable
import javax.inject.Inject
import kotlin.random.Random
class GradeWork @Inject constructor(
private val context: Context,
private val notificationManager: NotificationManagerCompat,
private val gradeRepository: GradeRepository,
private val preferencesRepository: PreferencesRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return gradeRepository.getGrades(student, semester, true, preferencesRepository.isNotificationsEnable)
.flatMap { gradeRepository.getNotNotifiedGrades(semester) }
.flatMapCompletable {
if (it.isNotEmpty()) notify(it)
gradeRepository.updateGrades(it.onEach { grade -> grade.isNotified = true })
}
}
private fun notify(grades: List<Grade>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, grades.size, grades.size))
.setContentText(context.resources.getQuantityString(R.plurals.grade_notify_new_items, grades.size, grades.size))
.setSmallIcon(R.drawable.ic_stat_notify_grade)
.setAutoCancel(true)
.setPriority(PRIORITY_HIGH)
.setDefaults(DEFAULT_ALL)
.setColor(context.getCompatColor(R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 0), FLAG_UPDATE_CURRENT))
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
grades.forEach { addLine("${it.subject}: ${it.entry}") }
this
})
.build()
)
}
}

View File

@ -0,0 +1,15 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.homework.HomeworkRepository
import io.reactivex.Completable
import org.threeten.bp.LocalDate.now
import javax.inject.Inject
class HomeworkWork @Inject constructor(private val homeworkRepository: HomeworkRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return homeworkRepository.getHomework(semester, now(), true).ignoreElement()
}
}

View File

@ -0,0 +1,55 @@
package io.github.wulkanowy.services.sync.works
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.DEFAULT_ALL
import androidx.core.app.NotificationCompat.PRIORITY_HIGH
import androidx.core.app.NotificationManagerCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable
import javax.inject.Inject
import kotlin.random.Random
class LuckyNumberWork @Inject constructor(
private val context: Context,
private val notificationManager: NotificationManagerCompat,
private val luckyNumberRepository: LuckyNumberRepository,
private val preferencesRepository: PreferencesRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return luckyNumberRepository.getLuckyNumber(semester, true, preferencesRepository.isNotificationsEnable)
.flatMap { luckyNumberRepository.getNotNotifiedLuckyNumber(semester) }
.flatMapCompletable {
notify(it)
luckyNumberRepository.updateLuckyNumber(it.apply { isNotified = true })
}
}
private fun notify(luckyNumber: LuckyNumber) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
.setContentTitle(context.getString(R.string.lucky_number_notify_new_item_title))
.setContentText(context.getString(R.string.lucky_number_notify_new_item, luckyNumber.luckyNumber))
.setSmallIcon(R.drawable.ic_stat_notify_lucky_number)
.setAutoCancel(true)
.setDefaults(DEFAULT_ALL)
.setPriority(PRIORITY_HIGH)
.setColor(context.getCompatColor(R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
)
.build())
}
}

View File

@ -0,0 +1,61 @@
package io.github.wulkanowy.services.sync.works
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.DEFAULT_ALL
import androidx.core.app.NotificationCompat.PRIORITY_HIGH
import androidx.core.app.NotificationManagerCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.message.MessageRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable
import javax.inject.Inject
import kotlin.random.Random
class MessageWork @Inject constructor(
private val context: Context,
private val notificationManager: NotificationManagerCompat,
private val messageRepository: MessageRepository,
private val preferencesRepository: PreferencesRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return messageRepository.getMessages(student, RECEIVED, true, preferencesRepository.isNotificationsEnable)
.flatMap { messageRepository.getNotNotifiedMessages(student) }
.flatMapCompletable {
if (it.isNotEmpty()) notify(it)
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })
}
}
private fun notify(messages: List<Message>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
.setContentTitle(context.resources.getQuantityString(R.plurals.message_new_items, messages.size, messages.size))
.setContentText(context.resources.getQuantityString(R.plurals.message_notify_new_items, messages.size, messages.size))
.setSmallIcon(R.drawable.ic_stat_notify_message)
.setAutoCancel(true)
.setDefaults(DEFAULT_ALL)
.setPriority(PRIORITY_HIGH)
.setColor(context.getCompatColor(R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
)
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, messages.size, messages.size))
messages.forEach { addLine("${it.sender}: ${it.subject}") }
this
})
.build())
}
}

View File

@ -0,0 +1,61 @@
package io.github.wulkanowy.services.sync.works
import android.app.PendingIntent
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.DEFAULT_ALL
import androidx.core.app.NotificationCompat.PRIORITY_HIGH
import androidx.core.app.NotificationManagerCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.note.NoteRepository
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable
import javax.inject.Inject
import kotlin.random.Random
class NoteWork @Inject constructor(
private val context: Context,
private val notificationManager: NotificationManagerCompat,
private val noteRepository: NoteRepository,
private val preferencesRepository: PreferencesRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return noteRepository.getNotes(student, semester, true, preferencesRepository.isNotificationsEnable)
.flatMap { noteRepository.getNotNotifiedNotes(student) }
.flatMapCompletable {
if (it.isNotEmpty()) notify(it)
noteRepository.updateNotes(it.onEach { note -> note.isNotified = true })
}
}
private fun notify(notes: List<Note>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewEntriesChannel.CHANNEL_ID)
.setContentTitle(context.resources.getQuantityString(R.plurals.note_new_items, notes.size, notes.size))
.setContentText(context.resources.getQuantityString(R.plurals.note_notify_new_items, notes.size, notes.size))
.setSmallIcon(R.drawable.ic_stat_notify_note)
.setAutoCancel(true)
.setDefaults(DEFAULT_ALL)
.setPriority(PRIORITY_HIGH)
.setColor(context.getCompatColor(R.color.colorPrimary))
.setContentIntent(
PendingIntent.getActivity(context, 0,
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
)
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
notes.forEach { addLine("${it.teacher}: ${it.category}") }
this
})
.build())
}
}

View File

@ -0,0 +1,24 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.recipient.RecipientRepository
import io.github.wulkanowy.data.repositories.reportingunit.ReportingUnitRepository
import io.reactivex.Completable
import javax.inject.Inject
class RecipientWork @Inject constructor(
private val reportingUnitRepository: ReportingUnitRepository,
private val recipientRepository: RecipientRepository
) : Work {
override fun create(student: Student, semester: Semester): Completable {
return reportingUnitRepository.getReportingUnits(student)
.flatMapCompletable { units ->
Completable.mergeDelayError(units.map {
recipientRepository.getRecipients(student, 2, it).ignoreElement()
})
}
}
}

View File

@ -0,0 +1,19 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Completable
import org.threeten.bp.LocalDate.now
import javax.inject.Inject
class TimetableWork @Inject constructor(private val timetableRepository: TimetableRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return timetableRepository.getTimetable(semester, now().monday, now().friday, true)
.ignoreElement()
}
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Completable
interface Work {
fun create(student: Student, semester: Semester): Completable
}

View File

@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.account
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.SchedulersProvider
@ -12,6 +13,7 @@ import javax.inject.Inject
class AccountPresenter @Inject constructor(
private val errorHandler: ErrorHandler,
private val studentRepository: StudentRepository,
private val syncManager: SyncManager,
private val schedulers: SchedulersProvider
) : BasePresenter<AccountView>(errorHandler) {
@ -48,6 +50,7 @@ class AccountPresenter @Inject constructor(
view?.apply {
if (it.isEmpty()) {
Timber.i("Logout result: Open login view")
syncManager.stopSyncWorker()
openClearLoginView()
} else {
Timber.i("Logout result: Switch to another student")

View File

@ -62,7 +62,7 @@ class GradeDetailsPresenter @Inject constructor(
Timber.i("Select mark grades as read")
disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getSemesters(it) }
.flatMap { gradeRepository.getNewGrades(it.first { item -> item.semesterId == currentSemesterId }) }
.flatMap { gradeRepository.getUnreadGrades(it.first { item -> item.semesterId == currentSemesterId }) }
.map { it.map { grade -> grade.apply { isRead = true } } }
.flatMapCompletable {
Timber.i("Mark as read ${it.size} grades")

View File

@ -14,7 +14,6 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem
import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavController.Companion.HIDE
import io.github.wulkanowy.R
import io.github.wulkanowy.services.notification.GradeNotification
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.modules.account.AccountDialog
import io.github.wulkanowy.ui.modules.attendance.AttendanceFragment
@ -164,10 +163,6 @@ class MainActivity : BaseActivity(), MainView {
presenter.onBackPressed { super.onBackPressed() }
}
override fun cancelNotifications() {
GradeNotification(applicationContext).cancelAll()
}
override fun openLoginView() {
startActivity(LoginActivity.getStartIntent(this)
.apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) })

View File

@ -4,7 +4,7 @@ import com.google.firebase.analytics.FirebaseAnalytics.Event.APP_OPEN
import com.google.firebase.analytics.FirebaseAnalytics.Param.DESTINATION
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.services.job.ServiceHelper
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
@ -17,8 +17,8 @@ class MainPresenter @Inject constructor(
private val errorHandler: ErrorHandler,
private val studentRepository: StudentRepository,
private val prefRepository: PreferencesRepository,
private val syncManager: SyncManager,
private val schedulers: SchedulersProvider,
private val serviceHelper: ServiceHelper,
private val analytics: FirebaseAnalyticsHelper
) : BasePresenter<MainView>(errorHandler) {
@ -26,11 +26,11 @@ class MainPresenter @Inject constructor(
super.onAttachView(view)
Timber.i("Main view is attached with $initMenuIndex menu index")
view.run {
cancelNotifications()
startMenuIndex = if (initMenuIndex != -1) initMenuIndex else prefRepository.startMenuIndex
initView()
}
serviceHelper.startFullSyncService()
syncManager.startSyncWorker()
analytics.logEvent(APP_OPEN, DESTINATION to when (initMenuIndex) {
1 -> "Grades"
@ -92,8 +92,7 @@ class MainPresenter @Inject constructor(
if (it.isNotEmpty()) {
Timber.i("Switching current student")
studentRepository.switchStudent(it[0])
}
else Completable.complete()
} else Completable.complete()
}
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)

View File

@ -26,8 +26,6 @@ interface MainView : BaseView {
fun popView()
fun cancelNotifications()
fun openLoginView()
interface MainChildView {

View File

@ -7,9 +7,9 @@ import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFolder.SENT
import io.github.wulkanowy.data.repositories.message.MessageRepository.MessageFolder.TRASHED
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.message.MessageFolder.SENT
import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.base.BaseFragmentPagerAdapter
import io.github.wulkanowy.ui.modules.main.MainActivity

View File

@ -12,7 +12,7 @@ import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.message.MessageRepository
import io.github.wulkanowy.data.repositories.message.MessageFolder
import io.github.wulkanowy.ui.base.session.BaseSessionFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.message.MessageFragment
@ -34,7 +34,7 @@ class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.Me
companion object {
const val MESSAGE_TAB_FOLDER_ID = "message_tab_folder_id"
fun newInstance(folder: MessageRepository.MessageFolder): MessageTabFragment {
fun newInstance(folder: MessageFolder): MessageTabFragment {
return MessageTabFragment().apply {
arguments = Bundle().apply {
putString(MESSAGE_TAB_FOLDER_ID, folder.name)
@ -56,7 +56,7 @@ class MessageTabFragment : BaseSessionFragment(), MessageTabView, MessageView.Me
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
messageContainer = messageTabRecycler
presenter.onAttachView(this, MessageRepository.MessageFolder.valueOf(
presenter.onAttachView(this, MessageFolder.valueOf(
(savedInstanceState ?: arguments)?.getString(MessageTabFragment.MESSAGE_TAB_FOLDER_ID) ?: ""
))
}

View File

@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.message.tab
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.repositories.message.MessageFolder
import io.github.wulkanowy.data.repositories.message.MessageRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
@ -20,9 +21,9 @@ class MessageTabPresenter @Inject constructor(
private val analytics: FirebaseAnalyticsHelper
) : BaseSessionPresenter<MessageTabView>(errorHandler) {
lateinit var folder: MessageRepository.MessageFolder
lateinit var folder: MessageFolder
fun onAttachView(view: MessageTabView, folder: MessageRepository.MessageFolder) {
fun onAttachView(view: MessageTabView, folder: MessageFolder) {
super.onAttachView(view)
view.initView()
this.folder = folder

View File

@ -2,7 +2,7 @@ package io.github.wulkanowy.ui.modules.settings
import com.readystatesoftware.chuck.api.ChuckCollector
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.job.ServiceHelper
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
@ -14,36 +14,25 @@ import javax.inject.Inject
class SettingsPresenter @Inject constructor(
errorHandler: ErrorHandler,
private val preferencesRepository: PreferencesRepository,
private val serviceHelper: ServiceHelper,
private val analytics: FirebaseAnalyticsHelper,
private val syncManager: SyncManager,
private val chuckCollector: ChuckCollector
) : BasePresenter<SettingsView>(errorHandler) {
override fun onAttachView(view: SettingsView) {
super.onAttachView(view)
Timber.i("Settings view is attached")
view.run {
setServicesSuspended(preferencesRepository.serviceEnablesKey, now().isHolidays)
}
view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays)
}
fun onSharedPreferenceChanged(key: String) {
Timber.i("Change settings $key")
preferencesRepository.apply {
when (key) {
preferencesRepository.serviceEnablesKey -> {
if (preferencesRepository.isServiceEnabled) serviceHelper.startFullSyncService()
else serviceHelper.stopFullSyncService()
}
preferencesRepository.servicesIntervalKey,
preferencesRepository.servicesOnlyWifiKey -> {
serviceHelper.reloadFullSyncService()
}
preferencesRepository.currentThemeKey -> {
view?.setTheme(preferencesRepository.currentTheme)
}
preferencesRepository.isShowChuckerNotificationKey -> {
chuckCollector.showNotification(preferencesRepository.isShowChuckerNotification)
serviceEnableKey -> syncManager.run { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
currentThemeKey -> view?.setTheme(currentTheme)
isShowChuckerNotificationKey -> chuckCollector.showNotification(isShowChuckerNotification)
}
}
analytics.logEvent("setting_changed", "name" to key)

View File

@ -3,13 +3,18 @@ package io.github.wulkanowy.utils
import android.content.Context
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
@ColorInt
fun Context.getThemeAttrColor(@AttrRes colorAttr: Int): Int {
val array = this.obtainStyledAttributes(null, intArrayOf(colorAttr))
try {
return array.getColor(0, 0)
val array = obtainStyledAttributes(null, intArrayOf(colorAttr))
return try {
array.getColor(0, 0)
} finally {
array.recycle()
}
}
@ColorInt
fun Context.getCompatColor(@ColorRes colorRes: Int) = ContextCompat.getColor(this, colorRes)

View File

@ -16,8 +16,8 @@
android:layout_height="40dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:tint="@android:color/black"
app:srcCompat="@drawable/ic_all_account_24dp" />
app:srcCompat="@drawable/ic_all_account_24dp"
app:tint="?android:textColorPrimary" />
<TextView
android:id="@+id/loginItemName"

View File

@ -1,6 +1,7 @@
<resources>
<string name="app_name">Wulkanowy</string>
<!--Activity/Fragment title-->
<string name="login_title">Wybierz ucznia</string>
<string name="main_title">Wulkanowy</string>
@ -70,17 +71,12 @@
<item quantity="many">%d ocen</item>
<item quantity="other">%d ocen</item>
</plurals>
<plurals name="grade_new_items">
<item quantity="one">Nowa ocena</item>
<item quantity="few">Nowe oceny</item>
<item quantity="many">Nowe oceny</item>
</plurals>
<!--Grade notify-->
<string name="notify_grade_channel">Nowe oceny</string>
<plurals name="notify_grade_new_items">
<plurals name="grade_notify_new_items">
<item quantity="one">Dostałeś %1$d ocenę</item>
<item quantity="few">"Dostałeś %1$d oceny</item>
<item quantity="many">Dostałeś %1$d ocen</item>
@ -88,16 +84,6 @@
</plurals>
<!--Note notify-->
<string name="notify_note_channel">Nowe uwagi</string>
<plurals name="notify_note_new_items">
<item quantity="one">Dostałeś %1$d uwagę</item>
<item quantity="few">"Dostałeś %1$d uwagi</item>
<item quantity="many">Dostałeś %1$d uwag</item>
<item quantity="other">Dostałeś %1$d uwag</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Lekcja</string>
<string name="timetable_room">Sala</string>
@ -106,6 +92,7 @@
<string name="timetable_changes">Zmiany</string>
<string name="timetable_no_items">Brak lekcji w tym dniu</string>
<!--CompletedLesson-->
<string name="completed_lessons_title">Lekcje zrealizowane</string>
<string name="completed_lessons_button">Zobacz lekcje zrealizowane</string>
@ -114,6 +101,7 @@
<string name="completed_lessons_absence">Nieobecność</string>
<string name="completed_lessons_resources">Zasoby</string>
<!--Attendance-->
<string name="attendance_summary_button">Podsumowanie frekwencji</string>
<string name="attendance_absence_school">Nieobecny z przyczyn szkolnych</string>
@ -131,9 +119,11 @@
<item quantity="many">%1$d nieobecności</item>
</plurals>
<!--Attendance summary-->
<string name="attendance_summary_final">Frekwencja</string>
<!--Exam-->
<string name="exam_no_items">Brak sprawdzianów w tym tygodniu</string>
<string name="exam_type">Typ</string>
@ -155,17 +145,12 @@
<item quantity="few">%d wiadomości</item>
<item quantity="many">%d wiadomości</item>
</plurals>
<plurals name="message_new_items">
<item quantity="one">Nowa wiadomość</item>
<item quantity="few">Nowe wiadomości</item>
<item quantity="many">Nowe wiadomości</item>
</plurals>
<!--Message notify-->
<string name="notify_message_channel">Nowe wiadomości</string>
<plurals name="notify_message_new_items">
<plurals name="message_notify_new_items">
<item quantity="one">Dostałeś %1$d wiadomość</item>
<item quantity="few">"Dostałeś %1$d wiadomości</item>
<item quantity="many">Dostałeś %1$d wiadomości</item>
@ -181,9 +166,6 @@
<string name="send_message_required_recipients">Musisz wybrać co najmniej 1 adresata</string>
<string name="send_message_content_min_length">Treść wiadomości musi zawierać co najmniej 3 znaki</string>
<!--About-->
<string name="about_source_code">Kod źródłowy</string>
<string name="about_feedback">Zgłoś błąd</string>
<!--Note-->
<string name="note_no_items">Brak informacji o uwagach</string>
@ -193,27 +175,31 @@
<item quantity="many">%d uwag</item>
<item quantity="other">%d uwag</item>
</plurals>
<plurals name="note_new_items">
<item quantity="one">Nowa uwaga</item>
<item quantity="few">Nowe uwagi</item>
<item quantity="many">Nowych uwag</item>
<item quantity="other">Nowych uwag</item>
</plurals>
<plurals name="note_notify_new_items">
<item quantity="one">Dostałeś %1$d uwagę</item>
<item quantity="few">"Dostałeś %1$d uwagi</item>
<item quantity="many">Dostałeś %1$d uwag</item>
<item quantity="other">Dostałeś %1$d uwag</item>
</plurals>
<!--Homework-->
<string name="homework_no_items">Brak zadań domowych</string>
<!--Lucky number-->
<string name="lucky_number_title">Szczęśliwy numerek</string>
<string name="lucky_number_header">Dzisiejszym szczęśliwym numerkiem jest</string>
<string name="lucky_number_empty">Brak informacji o szczęśliwym numerku</string>
<string name="lucky_number_notify_new_item_title">Szczęśliwy numerek na dzisiaj</string>
<string name="lucky_number_notify_new_item">Dziś szczęśliwym numerkiem jest: %d</string>
<!--Lucky number notify-->
<string name="notify_lucky_number_channel">Nowe szczęśliwe numerki</string>
<string name="notify_lucky_number_new_item_title">Szczęśliwy numerek na dzisiaj</string>
<string name="notify_lucky_number_new_item">Dziś szczęśliwym numerkiem jest: %d</string>
<!--Account-->
<string name="account_add_new">Dodaj konto</string>
@ -222,6 +208,11 @@
<string name="account_logout_student">Wylogowanie ucznia</string>
<!--About-->
<string name="about_source_code">Kod źródłowy</string>
<string name="about_feedback">Zgłoś błąd</string>
<!--Generic-->
<string name="all_content">Treść</string>
<string name="all_description">Opis</string>
@ -267,6 +258,10 @@
<string name="pref_services_wifi">Tylko WiFi</string>
<!--Notification Channels-->
<string name="channel_new_entries">Nowe wpisy w dzienniku</string>
<!--Colors-->
<string name="all_black">Czarny</string>
<string name="all_red">Czerwony</string>
@ -279,6 +274,7 @@
<!--Others-->
<string name="all_copied">Skopiowano</string>
<!--Errors-->
<string name="error_no_internet">Brak połączenia z internetem</string>
<string name="error_timeout">Zbyt długie oczekiwanie na połączenie</string>

View File

@ -1,6 +1,7 @@
<resources>
<string name="app_name">Wulkanowy</string>
<!--Activity/Fragment title-->
<string name="login_title">Select student</string>
<string name="main_title">Wulkanowy</string>
@ -68,26 +69,15 @@
<item quantity="one">%d grade</item>
<item quantity="other">%d grades</item>
</plurals>
<plurals name="grade_new_items">
<item quantity="one">New grade</item>
<item quantity="other">New grades</item>
</plurals>
<!--Grade notify-->
<string name="notify_grade_channel">New grades</string>
<plurals name="notify_grade_new_items">
<plurals name="grade_notify_new_items">
<item quantity="one">You received %1$d grade</item>
<item quantity="other">You received %1$d grades</item>
</plurals>
<!--Note notify-->
<string name="notify_note_channel">New notes</string>
<plurals name="notify_note_new_items">
<item quantity="one">You received %1$d note</item>
<item quantity="other">You received %1$d notes</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Lesson</string>
@ -97,6 +87,7 @@
<string name="timetable_changes">Changes</string>
<string name="timetable_no_items">No lessons this day</string>
<!--Completed lessons-->
<string name="completed_lessons_title">Completed lessons</string>
<string name="completed_lessons_button">Show completed lessons</string>
@ -105,6 +96,7 @@
<string name="completed_lessons_absence">Absence</string>
<string name="completed_lessons_resources">Resources</string>
<!--Attendance-->
<string name="attendance_summary_button">Attendance summary</string>
<string name="attendance_absence_school">Absent for school reasons</string>
@ -121,6 +113,7 @@
<item quantity="other">%1$d absences</item>
</plurals>
<!--Attendance summary-->
<string name="attendance_summary_final">Attendance</string>
@ -145,15 +138,11 @@
<item quantity="one">%d message</item>
<item quantity="other">%d messages</item>
</plurals>
<plurals name="message_new_items">
<item quantity="one">New message</item>
<item quantity="other">New messages</item>
</plurals>
<!--Message notify-->
<string name="notify_message_channel">New messages</string>
<plurals name="notify_message_new_items">
<plurals name="message_notify_new_items">
<item quantity="one">You received %1$d message</item>
<item quantity="other">You received %1$d messages</item>
</plurals>
@ -168,9 +157,6 @@
<string name="send_message_required_recipients">You need to choose at least 1 recipient</string>
<string name="send_message_content_min_length">The message content must be at least 3 characters</string>
<!--About-->
<string name="about_source_code">Source code</string>
<string name="about_feedback">Report a bug</string>
<!--Note-->
<string name="note_no_items">No info about notes</string>
@ -178,25 +164,27 @@
<item quantity="one">%d note</item>
<item quantity="other">%d notes</item>
</plurals>
<plurals name="note_new_items">
<item quantity="one">New note</item>
<item quantity="other">New notes</item>
</plurals>
<plurals name="note_notify_new_items">
<item quantity="one">You received %1$d note</item>
<item quantity="other">You received %1$d notes</item>
</plurals>
<!--Homework-->
<string name="homework_no_items">No info about homework</string>
<!--Lucky number-->
<string name="lucky_number_title">Lucky number</string>
<string name="lucky_number_header">Today\'s lucky number is</string>
<string name="lucky_number_empty">No info about the lucky number</string>
<string name="lucky_number_notify_new_item_title">Lucky number for today</string>
<string name="lucky_number_notify_new_item">Today\'s lucky number is: %d</string>
<!--Lucky number notify-->
<string name="notify_lucky_number_channel">New lucky numbers</string>
<string name="notify_lucky_number_new_item_title">Lucky number for today</string>
<string name="notify_lucky_number_new_item">Today\'s lucky number is: %d</string>
<!--Account-->
<string name="account_add_new">Add account</string>
@ -205,6 +193,11 @@
<string name="account_logout_student">Student logout</string>
<!--About-->
<string name="about_source_code">Source code</string>
<string name="about_feedback">Report a bug</string>
<!--Generic-->
<string name="all_content">Content</string>
<string name="all_description">Description</string>
@ -250,6 +243,10 @@
<string name="pref_services_wifi">Wi-Fi only</string>
<!--Notification Channels-->
<string name="channel_new_entries">New entries in register</string>
<!--Colors-->
<string name="all_black">Black</string>
<string name="all_red">Red</string>
@ -262,6 +259,7 @@
<!--Others-->
<string name="all_copied">Copied</string>
<!--Errors-->
<string name="error_no_internet">No internet connection</string>
<string name="error_timeout">Too long wait for connection</string>

View File

@ -3,7 +3,7 @@ package io.github.wulkanowy.ui.modules.main
import io.github.wulkanowy.TestSchedulersProvider
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.services.job.ServiceHelper
import io.github.wulkanowy.services.sync.SyncManager
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import org.junit.Before
@ -25,7 +25,7 @@ class MainPresenterTest {
lateinit var prefRepository: PreferencesRepository
@Mock
lateinit var serviceHelper: ServiceHelper
lateinit var syncManager: SyncManager
@Mock
lateinit var mainView: MainView
@ -40,7 +40,7 @@ class MainPresenterTest {
MockitoAnnotations.initMocks(this)
clearInvocations(mainView)
presenter = MainPresenter(errorHandler, studentRepository, prefRepository, TestSchedulersProvider(), serviceHelper, analytics)
presenter = MainPresenter(errorHandler, studentRepository, prefRepository, syncManager, TestSchedulersProvider(), analytics)
presenter.onAttachView(mainView, -1)
}