1
0

Compare commits

..

29 Commits

Author SHA1 Message Date
fc9e558cd6 Merge branch 'release/0.17.3' 2020-04-23 16:22:44 +02:00
68140bd544 Version 0.17.3 2020-04-23 16:22:39 +02:00
2c4c2d1f49 Fix injector of ErrorDialog (#780) 2020-04-23 11:07:18 +02:00
4894086d9d Bump about_libraries from 8.1.1 to 8.1.2 (#779) 2020-04-21 16:21:44 +00:00
1d29ef5fe3 Merge tag '0.17.2' into develop
Version 0.17.2
2020-04-19 23:42:00 +02:00
7fa333cff2 Merge branch 'release/0.17.2' 2020-04-19 23:41:53 +02:00
c1ffc2ae72 Version 0.17.2 2020-04-19 23:37:29 +02:00
9c0e2dc533 Refresh semesters if previous list was downloaded in different m… (#776) 2020-04-19 23:21:59 +02:00
9b18e3669d Fix crash after send message when activity is in background (#777) 2020-04-19 23:21:25 +02:00
366ebc781d Add error message and bug report button to error dialog (#778) 2020-04-19 23:20:55 +02:00
4bd0459155 Don't log common errors to crashlytics (#775) 2020-04-18 23:07:20 +02:00
b19084cb57 Fix visibility of dialog close button when homework content is l… (#774) 2020-04-18 23:06:05 +02:00
69be7ca412 Bump kotlin_version from 1.3.71 to 1.3.72 (#773) 2020-04-17 21:01:41 +00:00
07307b9709 Bump swiperefreshlayout from 1.1.0-beta01 to 1.1.0-rc01 (#770) 2020-04-17 20:59:02 +00:00
ee4a5e56a9 Bump gradle from 3.6.2 to 3.6.3 (#772) 2020-04-17 20:37:38 +00:00
c8f8ec77a9 Bump preference-ktx from 1.1.0 to 1.1.1 (#771) 2020-04-17 20:35:24 +00:00
be46a43427 Merge tag '0.17.1' into develop
Version 0.17.1
2020-04-12 19:20:59 +02:00
183e379223 Merge branch 'release/0.17.1' 2020-04-12 19:20:53 +02:00
2350fc2ddf Version 0.17.1 2020-04-12 19:20:44 +02:00
152f966a66 Bump firebase-inappmessaging-display-ktx from 19.0.4 to 19.0.5 (#767) 2020-04-12 17:19:06 +00:00
85ee7fad1d Bump firebase-inappmessaging-ktx from 19.0.4 to 19.0.5 (#768) 2020-04-12 16:58:23 +00:00
3ac085573f Show all known adfslight registers in register list (#766) 2020-04-12 18:55:16 +02:00
64a19d9627 Bump about_libraries from 8.1.0 to 8.1.1 (#769) 2020-04-12 15:14:08 +00:00
76af623c94 Add Sdk.init(student) call in all remote repositories (#764) 2020-04-12 15:13:35 +02:00
11c285be01 Fix homework dialog size (#765) 2020-04-12 15:12:25 +02:00
a0528496eb Fix crash caused by updating view in not attached fragment (#763) 2020-04-09 23:46:42 +02:00
299345b864 Fix crash in message preview (#762) 2020-04-09 23:30:56 +02:00
0a18fefb1f Use recycler view in homework details dialog (#761) 2020-04-08 18:17:20 +02:00
a26f0ec8c8 Merge tag '0.17.0' into develop
Version 0.17.0
2020-04-05 18:42:42 +02:00
123 changed files with 1549 additions and 915 deletions

View File

@ -14,7 +14,7 @@ cache:
branches: branches:
only: only:
- develop - develop
- 0.17.0 - 0.17.3
android: android:
licenses: licenses:

View File

@ -18,8 +18,8 @@ android {
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 29 targetSdkVersion 29
versionCode 54 versionCode 56
versionName "0.17.0" versionName "0.17.2"
multiDexEnabled true multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@ -128,7 +128,7 @@ configurations.all {
} }
dependencies { dependencies {
implementation "io.github.wulkanowy:sdk:0.17.0" implementation "io.github.wulkanowy:sdk:0.17.3"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.core:core-ktx:1.2.0"
@ -139,10 +139,10 @@ dependencies {
implementation "androidx.annotation:annotation:1.1.0" implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1" implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.preference:preference-ktx:1.1.0" implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.0" implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-beta01" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-rc01"
implementation "androidx.constraintlayout:constraintlayout:1.1.3" implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.1.0" implementation "com.google.android.material:material:1.1.0"
@ -187,8 +187,8 @@ dependencies {
implementation "io.coil-kt:coil:0.9.5" implementation "io.coil-kt:coil:0.9.5"
playImplementation 'com.google.firebase:firebase-analytics:17.3.0' playImplementation 'com.google.firebase:firebase-analytics:17.3.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.4' playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.5'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.4" playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.5"
playImplementation "com.google.firebase:firebase-messaging:20.1.0" playImplementation "com.google.firebase:firebase-messaging:20.1.0"
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1" playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'

View File

@ -0,0 +1,29 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.entities.Student
import org.threeten.bp.LocalDateTime
fun getStudent(): Student {
return Student(
email = "test",
password = "test123",
schoolSymbol = "23",
scrapperBaseUrl = "fakelog.cf",
loginType = "AUTO",
isCurrent = true,
studentName = "",
schoolShortName = "",
schoolName = "",
studentId = 0,
classId = 1,
symbol = "",
registrationDate = LocalDateTime.now(),
className = "",
loginMode = "API",
certificateKey = "",
privateKey = "",
mobileBaseUrl = "",
userLoginId = 0,
isParent = false
)
}

View File

@ -5,13 +5,11 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.repositories.getStudent
import io.github.wulkanowy.data.db.entities.Student
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.threeten.bp.LocalDateTime.now
import kotlin.test.assertEquals import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -21,14 +19,13 @@ class StudentLocalTest {
private lateinit var testDb: AppDatabase private lateinit var testDb: AppDatabase
private lateinit var sharedProvider: SharedPrefProvider private val student = getStudent()
@Before @Before
fun createDb() { fun createDb() {
val context = ApplicationProvider.getApplicationContext<Context>() val context = ApplicationProvider.getApplicationContext<Context>()
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build() .build()
sharedProvider = SharedPrefProvider(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
studentLocal = StudentLocal(testDb.studentDao, context) studentLocal = StudentLocal(testDb.studentDao, context)
} }
@ -39,8 +36,7 @@ class StudentLocalTest {
@Test @Test
fun saveAndReadTest() { fun saveAndReadTest() {
studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", scrapperBaseUrl = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolShortName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "", loginMode = "API", certificateKey = "", privateKey = "", mobileBaseUrl = "", userLoginId = 0, isParent = false))) studentLocal.saveStudents(listOf(student)).blockingGet()
.blockingGet()
val student = studentLocal.getCurrentStudent(true).blockingGet() val student = studentLocal.getCurrentStudent(true).blockingGet()
assertEquals("23", student.schoolSymbol) assertEquals("23", student.schoolSymbol)

View File

@ -9,6 +9,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.github.wulkanowy.data.repositories.getStudent
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.mockk.MockKAnnotations import io.mockk.MockKAnnotations
import io.mockk.every import io.mockk.every
@ -33,6 +34,8 @@ class TimetableRepositoryTest {
.strategy(TestInternetObservingStrategy()) .strategy(TestInternetObservingStrategy())
.build() .build()
private val student = getStudent()
@MockK @MockK
private lateinit var semesterMock: Semester private lateinit var semesterMock: Semester
@ -78,7 +81,7 @@ class TimetableRepositoryTest {
)) ))
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote) val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
.getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true) .getTimetable(student, semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
.blockingGet() .blockingGet()
assertEquals(4, lessons.size) assertEquals(4, lessons.size)
@ -124,7 +127,7 @@ class TimetableRepositoryTest {
)) ))
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote) val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
.getTimetable(semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true) .getTimetable(student, semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true)
.blockingGet() .blockingGet()
assertEquals(12, lessons.size) assertEquals(12, lessons.size)

View File

@ -1,30 +0,0 @@
package io.github.wulkanowy.data
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import javax.inject.Inject
class SdkHelper @Inject constructor(private val sdk: Sdk) {
fun init(student: Student) {
sdk.apply {
email = student.email
password = student.password
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
classId = student.classId
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
scrapperBaseUrl = student.scrapperBaseUrl
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
}
loginId = student.userLoginId
mode = Sdk.Mode.valueOf(student.loginMode)
mobileBaseUrl = student.mobileBaseUrl
certKey = student.certificateKey
privateKey = student.privateKey
}
}
}

View File

@ -22,6 +22,9 @@ interface StudentDao {
@Query("SELECT * FROM Students WHERE is_current = 1") @Query("SELECT * FROM Students WHERE is_current = 1")
fun loadCurrent(): Maybe<Student> fun loadCurrent(): Maybe<Student>
@Query("SELECT * FROM Students WHERE id = :id")
fun loadById(id: Int): Maybe<Student>
@Query("SELECT * FROM Students") @Query("SELECT * FROM Students")
fun loadAll(): Maybe<List<Student>> fun loadAll(): Maybe<List<Student>>

View File

@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime
@ -14,8 +16,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class AttendanceRemote @Inject constructor(private val sdk: Sdk) { class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> { fun getAttendance(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendance(startDate, endDate, semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendance(startDate, endDate, semester.semesterId)
.map { attendance -> .map { attendance ->
attendance.map { attendance.map {
Attendance( Attendance(
@ -39,8 +42,8 @@ class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
} }
} }
fun excuseAbsence(semester: Semester, absenceList: List<Attendance>, reason: String?): Single<Boolean> { fun excuseAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String?): Single<Boolean> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance -> return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
Absent( Absent(
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)), date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
timeId = attendance.timeId timeId = attendance.timeId

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -20,29 +21,25 @@ class AttendanceRepository @Inject constructor(
private val remote: AttendanceRemote private val remote: AttendanceRemote
) { ) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean) fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean): Single<List<Attendance>> {
: Single<List<Attendance>> { return local.getAttendance(semester, start.monday, end.friday).filter { !forceRefresh }
return Single.fromCallable { startDate.monday to endDate.friday } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
.flatMap { dates -> if (it) remote.getAttendance(student, semester, start.monday, end.friday)
local.getAttendance(semester, dates.first, dates.second).filter { !forceRefresh } else Single.error(UnknownHostException())
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap { }.flatMap { newAttendance ->
if (it) remote.getAttendance(semester, dates.first, dates.second) local.getAttendance(semester, start.monday, end.friday)
else Single.error(UnknownHostException()) .toSingle(emptyList())
}.flatMap { newAttendance -> .doOnSuccess { oldAttendance ->
local.getAttendance(semester, dates.first, dates.second) local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
.toSingle(emptyList()) local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
.doOnSuccess { oldAttendance -> }
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance)) }.flatMap {
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance)) local.getAttendance(semester, start.monday, end.friday)
} .toSingle(emptyList())
}.flatMap { }).map { list -> list.filter { it.date in start..end } }
local.getAttendance(semester, dates.first, dates.second)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
} }
fun excuseForAbsence(semester: Semester, attendanceList: List<Attendance>, reason: String? = null): Single<Boolean> { fun excuseForAbsence(student: Student, semester: Semester, attendanceList: List<Attendance>, reason: String? = null): Single<Boolean> {
return remote.excuseAbsence(semester, attendanceList, reason) return remote.excuseAbsence(student, semester, attendanceList, reason)
} }
} }

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.attendancesummary
import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -10,8 +12,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) { class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendanceSummary(semester: Semester, subjectId: Int): Single<List<AttendanceSummary>> { fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int): Single<List<AttendanceSummary>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendanceSummary(subjectId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendanceSummary(subjectId)
.map { attendance -> .map { attendance ->
attendance.map { attendance.map {
AttendanceSummary( AttendanceSummary(

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single import io.reactivex.Single
import java.net.UnknownHostException import java.net.UnknownHostException
@ -17,11 +18,11 @@ class AttendanceSummaryRepository @Inject constructor(
private val remote: AttendanceSummaryRemote private val remote: AttendanceSummaryRemote
) { ) {
fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>> { fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>> {
return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh } return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getAttendanceSummary(semester, subjectId) if (it) remote.getAttendanceSummary(student, semester, subjectId)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.completedlessons
import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import javax.inject.Inject import javax.inject.Inject
@ -11,8 +13,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) { class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) {
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> { fun getCompletedLessons(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getCompletedLessons(startDate, endDate) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getCompletedLessons(startDate, endDate)
.map { lessons -> .map { lessons ->
lessons.map { lessons.map {
it.absence it.absence

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -20,25 +21,22 @@ class CompletedLessonsRepository @Inject constructor(
private val remote: CompletedLessonsRemote private val remote: CompletedLessonsRemote
) { ) {
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> { fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> {
return Single.fromCallable { startDate.monday to endDate.friday } return local.getCompletedLessons(semester, start.monday, end.friday).filter { !forceRefresh }
.flatMap { dates -> .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
local.getCompletedLessons(semester, dates.first, dates.second).filter { !forceRefresh } .flatMap {
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) if (it) remote.getCompletedLessons(student, semester, start.monday, end.friday)
.flatMap { else Single.error(UnknownHostException())
if (it) remote.getCompletedLessons(semester, dates.first, dates.second) }.flatMap { new ->
else Single.error(UnknownHostException()) local.getCompletedLessons(semester, start.monday, end.friday)
}.flatMap { new -> .toSingle(emptyList())
local.getCompletedLessons(semester, dates.first, dates.second) .doOnSuccess { old ->
.toSingle(emptyList()) local.deleteCompleteLessons(old.uniqueSubtract(new))
.doOnSuccess { old -> local.saveCompletedLessons(new.uniqueSubtract(old))
local.deleteCompleteLessons(old.uniqueSubtract(new)) }
local.saveCompletedLessons(new.uniqueSubtract(old)) }.flatMap {
} local.getCompletedLessons(semester, start.monday, end.friday)
}.flatMap { .toSingle(emptyList())
local.getCompletedLessons(semester, dates.first, dates.second) }).map { list -> list.filter { it.date in start..end } }
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
} }
} }

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import javax.inject.Inject import javax.inject.Inject
@ -11,8 +13,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class ExamRemote @Inject constructor(private val sdk: Sdk) { class ExamRemote @Inject constructor(private val sdk: Sdk) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> { fun getExams(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getExams(startDate, endDate, semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getExams(startDate, endDate, semester.semesterId)
.map { exams -> .map { exams ->
exams.map { exams.map {
Exam( Exam(

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -20,25 +21,22 @@ class ExamRepository @Inject constructor(
private val remote: ExamRemote private val remote: ExamRemote
) { ) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> { fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
return Single.fromCallable { startDate.monday to endDate.friday } return local.getExams(semester, start.monday, end.friday).filter { !forceRefresh }
.flatMap { dates -> .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
local.getExams(semester, dates.first, dates.second).filter { !forceRefresh } .flatMap {
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) if (it) remote.getExams(student, semester, start.monday, end.friday)
.flatMap { else Single.error(UnknownHostException())
if (it) remote.getExams(semester, dates.first, dates.second) }.flatMap { new ->
else Single.error(UnknownHostException()) local.getExams(semester, start.monday, end.friday)
}.flatMap { new -> .toSingle(emptyList())
local.getExams(semester, dates.first, dates.second) .doOnSuccess { old ->
.toSingle(emptyList()) local.deleteExams(old.uniqueSubtract(new))
.doOnSuccess { old -> local.saveExams(new.uniqueSubtract(old))
local.deleteExams(old.uniqueSubtract(new)) }
local.saveExams(new.uniqueSubtract(old)) }.flatMap {
} local.getExams(semester, start.monday, end.friday)
}.flatMap { .toSingle(emptyList())
local.getExams(semester, dates.first, dates.second) }).map { list -> list.filter { it.date in start..end } }
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
} }
} }

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -10,8 +12,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class GradeRemote @Inject constructor(private val sdk: Sdk) { class GradeRemote @Inject constructor(private val sdk: Sdk) {
fun getGrades(semester: Semester): Single<List<Grade>> { fun getGrades(student: Student, semester: Semester): Single<List<Grade>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGrades(semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGrades(semester.semesterId)
.map { grades -> .map { grades ->
grades.map { grades.map {
Grade( Grade(

View File

@ -23,7 +23,7 @@ class GradeRepository @Inject constructor(
return local.getGrades(semester).filter { !forceRefresh } return local.getGrades(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getGrades(semester) if (it) remote.getGrades(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getGrades(semester).toSingle(emptyList()) local.getGrades(semester).toSingle(emptyList())

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.gradessummary
import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -10,8 +12,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class GradeSummaryRemote @Inject constructor(private val sdk: Sdk) { class GradeSummaryRemote @Inject constructor(private val sdk: Sdk) {
fun getGradeSummary(semester: Semester): Single<List<GradeSummary>> { fun getGradeSummary(student: Student, semester: Semester): Single<List<GradeSummary>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesSummary(semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesSummary(semester.semesterId)
.map { gradesSummary -> .map { gradesSummary ->
gradesSummary.map { gradesSummary.map {
GradeSummary( GradeSummary(

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single import io.reactivex.Single
import java.net.UnknownHostException import java.net.UnknownHostException
@ -17,11 +18,11 @@ class GradeSummaryRepository @Inject constructor(
private val remote: GradeSummaryRemote private val remote: GradeSummaryRemote
) { ) {
fun getGradesSummary(semester: Semester, forceRefresh: Boolean = false): Single<List<GradeSummary>> { fun getGradesSummary(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<GradeSummary>> {
return local.getGradesSummary(semester).filter { !forceRefresh } return local.getGradesSummary(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getGradeSummary(semester) if (it) remote.getGradeSummary(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getGradesSummary(semester).toSingle(emptyList()) local.getGradesSummary(semester).toSingle(emptyList())

View File

@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.gradestatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -11,8 +13,8 @@ import javax.inject.Singleton
@Singleton @Singleton
class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) { class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
fun getGradeStatistics(semester: Semester, isSemester: Boolean): Single<List<GradeStatistics>> { fun getGradeStatistics(student: Student, semester: Semester, isSemester: Boolean): Single<List<GradeStatistics>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).let { return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).let {
if (isSemester) it.getGradesAnnualStatistics(semester.semesterId) if (isSemester) it.getGradesAnnualStatistics(semester.semesterId)
else it.getGradesPartialStatistics(semester.semesterId) else it.getGradesPartialStatistics(semester.semesterId)
}.map { gradeStatistics -> }.map { gradeStatistics ->
@ -29,8 +31,9 @@ class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) {
} }
} }
fun getGradePointsStatistics(semester: Semester): Single<List<GradePointsStatistics>> { fun getGradePointsStatistics(student: Student, semester: Semester): Single<List<GradePointsStatistics>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesPointsStatistics(semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getGradesPointsStatistics(semester.semesterId)
.map { gradePointsStatistics -> .map { gradePointsStatistics ->
gradePointsStatistics.map { gradePointsStatistics.map {
GradePointsStatistics( GradePointsStatistics(

View File

@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GradeStatisticsItem import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -20,11 +21,11 @@ class GradeStatisticsRepository @Inject constructor(
private val remote: GradeStatisticsRemote private val remote: GradeStatisticsRemote
) { ) {
fun getGradesStatistics(semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single<List<GradeStatisticsItem>> { fun getGradesStatistics(student: Student, semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single<List<GradeStatisticsItem>> {
return local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.filter { !forceRefresh } return local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getGradeStatistics(semester, isSemester) if (it) remote.getGradeStatistics(student, semester, isSemester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getGradesStatistics(semester, isSemester).toSingle(emptyList()) local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
@ -35,11 +36,11 @@ class GradeStatisticsRepository @Inject constructor(
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.toSingle(emptyList()) }) }.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.toSingle(emptyList()) })
} }
fun getGradesPointsStatistics(semester: Semester, subjectName: String, forceRefresh: Boolean): Single<List<GradeStatisticsItem>> { fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean): Single<List<GradeStatisticsItem>> {
return local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.filter { !forceRefresh } return local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getGradePointsStatistics(semester) if (it) remote.getGradePointsStatistics(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getGradesPointsStatistics(semester).toSingle(emptyList()) local.getGradesPointsStatistics(semester).toSingle(emptyList())

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.homework
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import javax.inject.Inject import javax.inject.Inject
@ -11,8 +13,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class HomeworkRemote @Inject constructor(private val sdk: Sdk) { class HomeworkRemote @Inject constructor(private val sdk: Sdk) {
fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Homework>> { fun getHomework(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Homework>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getHomework(startDate, endDate) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getHomework(startDate, endDate)
.map { homework -> .map { homework ->
homework.map { homework.map {
Homework( Homework(

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -21,12 +22,12 @@ class HomeworkRepository @Inject constructor(
private val remote: HomeworkRemote private val remote: HomeworkRemote
) { ) {
fun getHomework(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Homework>> { fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Homework>> {
return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) -> return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) ->
local.getHomework(semester, monday, friday).filter { !forceRefresh } local.getHomework(semester, monday, friday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getHomework(semester, monday, friday) if (it) remote.getHomework(student, semester, monday, friday)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getHomework(semester, monday, friday).toSingle(emptyList()) local.getHomework(semester, monday, friday).toSingle(emptyList())

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.luckynumber
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Maybe import io.reactivex.Maybe
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import javax.inject.Inject import javax.inject.Inject
@ -12,7 +13,7 @@ import javax.inject.Singleton
class LuckyNumberRemote @Inject constructor(private val sdk: Sdk) { class LuckyNumberRemote @Inject constructor(private val sdk: Sdk) {
fun getLuckyNumber(student: Student): Maybe<LuckyNumber> { fun getLuckyNumber(student: Student): Maybe<LuckyNumber> {
return sdk.getLuckyNumber(student.schoolShortName).map { return sdk.init(student).getLuckyNumber(student.schoolShortName).map {
LuckyNumber( LuckyNumber(
studentId = student.studentId, studentId = student.studentId,
date = LocalDate.now(), date = LocalDate.now(),

View File

@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.luckynumber
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.SdkHelper
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Completable import io.reactivex.Completable
@ -16,36 +15,33 @@ import javax.inject.Singleton
class LuckyNumberRepository @Inject constructor( class LuckyNumberRepository @Inject constructor(
private val settings: InternetObservingSettings, private val settings: InternetObservingSettings,
private val local: LuckyNumberLocal, private val local: LuckyNumberLocal,
private val remote: LuckyNumberRemote, private val remote: LuckyNumberRemote
private val sdkHelper: SdkHelper
) { ) {
fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe<LuckyNumber> { fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe<LuckyNumber> {
return Maybe.just(sdkHelper.init(student)).flatMap { return local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh }
local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMapMaybe {
.flatMapMaybe { if (it) remote.getLuckyNumber(student)
if (it) remote.getLuckyNumber(student) else Maybe.error(UnknownHostException())
else Maybe.error(UnknownHostException()) }.flatMap { new ->
}.flatMap { new -> local.getLuckyNumber(student, LocalDate.now())
local.getLuckyNumber(student, LocalDate.now()) .doOnSuccess { old ->
.doOnSuccess { old -> if (new != old) {
if (new != old) { local.deleteLuckyNumber(old)
local.deleteLuckyNumber(old)
local.saveLuckyNumber(new.apply {
if (notify) isNotified = false
})
}
}
.doOnComplete {
local.saveLuckyNumber(new.apply { local.saveLuckyNumber(new.apply {
if (notify) isNotified = false if (notify) isNotified = false
}) })
} }
}.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) }, }
{ local.getLuckyNumber(student, LocalDate.now()) }) .doOnComplete {
) local.saveLuckyNumber(new.apply {
} if (notify) isNotified = false
})
}
}.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) },
{ local.getLuckyNumber(student, LocalDate.now()) })
)
} }
fun getNotNotifiedLuckyNumber(student: Student): Maybe<LuckyNumber> { fun getNotNotifiedLuckyNumber(student: Student): Maybe<LuckyNumber> {

View File

@ -8,6 +8,7 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.sdk.pojo.SentMessage import io.github.wulkanowy.sdk.pojo.SentMessage
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDateTime.now import org.threeten.bp.LocalDateTime.now
import javax.inject.Inject import javax.inject.Inject
@ -18,7 +19,7 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
class MessageRemote @Inject constructor(private val sdk: Sdk) { class MessageRemote @Inject constructor(private val sdk: Sdk) {
fun getMessages(student: Student, semester: Semester, folder: MessageFolder): Single<List<Message>> { fun getMessages(student: Student, semester: Semester, folder: MessageFolder): Single<List<Message>> {
return sdk.getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages -> return sdk.init(student).getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages ->
messages.map { messages.map {
Message( Message(
studentId = student.id.toInt(), studentId = student.id.toInt(),
@ -41,8 +42,8 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
} }
} }
fun getMessagesContentDetails(message: Message, markAsRead: Boolean = false): Single<Pair<String, List<MessageAttachment>>> { fun getMessagesContentDetails(student: Student, message: Message, markAsRead: Boolean = false): Single<Pair<String, List<MessageAttachment>>> {
return sdk.getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details -> return sdk.init(student).getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details ->
details.content to details.attachments.map { details.content to details.attachments.map {
MessageAttachment( MessageAttachment(
realId = it.id, realId = it.id,
@ -55,8 +56,8 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
} }
} }
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> { fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
return sdk.sendMessage( return sdk.init(student).sendMessage(
subject = subject, subject = subject,
content = content, content = content,
recipients = recipients.map { recipients = recipients.map {
@ -73,7 +74,7 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) {
) )
} }
fun deleteMessage(message: Message): Single<Boolean> { fun deleteMessage(student: Student, message: Message): Single<Boolean> {
return sdk.deleteMessages(listOf(Pair(message.realId, message.folderId))) return sdk.init(student).deleteMessages(listOf(Pair(message.realId, message.folderId)))
} }
} }

View File

@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.message
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.SdkHelper
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
@ -22,60 +21,53 @@ import javax.inject.Singleton
class MessageRepository @Inject constructor( class MessageRepository @Inject constructor(
private val settings: InternetObservingSettings, private val settings: InternetObservingSettings,
private val local: MessageLocal, private val local: MessageLocal,
private val remote: MessageRemote, private val remote: MessageRemote
private val sdkHelper: SdkHelper
) { ) {
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Message>> { fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Message>> {
return Single.just(sdkHelper.init(student)) return local.getMessages(student, folder).filter { !forceRefresh }
.flatMap { _ -> .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
local.getMessages(student, folder).filter { !forceRefresh } .flatMap {
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) if (it) remote.getMessages(student, semester, folder)
.flatMap { else Single.error(UnknownHostException())
if (it) remote.getMessages(student, semester, folder) }.flatMap { new ->
else Single.error(UnknownHostException()) local.getMessages(student, folder).toSingle(emptyList())
}.flatMap { new -> .doOnSuccess { old ->
local.getMessages(student, folder).toSingle(emptyList()) local.deleteMessages(old.uniqueSubtract(new))
.doOnSuccess { old -> local.saveMessages(new.uniqueSubtract(old)
local.deleteMessages(old.uniqueSubtract(new)) .onEach {
local.saveMessages(new.uniqueSubtract(old) it.isNotified = !notify
.onEach { })
it.isNotified = !notify }
}) }.flatMap { local.getMessages(student, folder).toSingle(emptyList()) }
} )
}.flatMap { local.getMessages(student, folder).toSingle(emptyList()) }
)
}
} }
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false): Single<MessageWithAttachment> { fun getMessage(student: Student, message: Message, markAsRead: Boolean = false): Single<MessageWithAttachment> {
return Single.just(sdkHelper.init(student)) return local.getMessageWithAttachment(student, message)
.flatMap { _ -> .filter {
local.getMessageWithAttachment(student, message) it.message.content.isNotEmpty().also { status ->
.filter { Timber.d("Message content in db empty: ${!status}")
it.message.content.isNotEmpty().also { status -> } && !it.message.unread
Timber.d("Message content in db empty: ${!status}")
} && !it.message.unread
}
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) local.getMessageWithAttachment(student, message)
else Single.error(UnknownHostException())
}
.flatMap { dbMessage ->
remote.getMessagesContentDetails(dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) ->
local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply {
id = dbMessage.message.id
content = content.ifBlank { downloadedMessage }
}))
local.saveMessageAttachments(attachments)
Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read")
}
}.flatMap {
local.getMessageWithAttachment(student, message)
}
)
} }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) local.getMessageWithAttachment(student, message)
else Single.error(UnknownHostException())
}
.flatMap { dbMessage ->
remote.getMessagesContentDetails(student, dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) ->
local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply {
id = dbMessage.message.id
content = content.ifBlank { downloadedMessage }
}))
local.saveMessageAttachments(attachments)
Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read")
}
}.flatMap {
local.getMessageWithAttachment(student, message)
}
)
} }
fun getNotNotifiedMessages(student: Student): Single<List<Message>> { fun getNotNotifiedMessages(student: Student): Single<List<Message>> {
@ -88,18 +80,18 @@ class MessageRepository @Inject constructor(
return Completable.fromCallable { local.updateMessages(messages) } return Completable.fromCallable { local.updateMessages(messages) }
} }
fun sendMessage(subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> { fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): Single<SentMessage> {
return ReactiveNetwork.checkInternetConnectivity(settings) return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.sendMessage(subject, content, recipients) if (it) remote.sendMessage(student, subject, content, recipients)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
} }
} }
fun deleteMessage(message: Message): Single<Boolean> { fun deleteMessage(student: Student, message: Message): Single<Boolean> {
return ReactiveNetwork.checkInternetConnectivity(settings) return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.deleteMessage(message) if (it) remote.deleteMessage(student, message)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
} }
.doOnSuccess { .doOnSuccess {

View File

@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.mobiledevice
import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -11,13 +13,14 @@ import javax.inject.Singleton
@Singleton @Singleton
class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) { class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) {
fun getDevices(semester: Semester): Single<List<MobileDevice>> { fun getDevices(student: Student, semester: Semester): Single<List<MobileDevice>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getRegisteredDevices() return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getRegisteredDevices()
.map { devices -> .map { devices ->
devices.map { devices.map {
MobileDevice( MobileDevice(
studentId = semester.studentId, studentId = semester.studentId,
date = it.date, date = it.createDate,
deviceId = it.id, deviceId = it.id,
name = it.name name = it.name
) )
@ -25,12 +28,14 @@ class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) {
} }
} }
fun unregisterDevice(semester: Semester, device: MobileDevice): Single<Boolean> { fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice): Single<Boolean> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).unregisterDevice(device.deviceId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.unregisterDevice(device.deviceId)
} }
fun getToken(semester: Semester): Single<MobileDeviceToken> { fun getToken(student: Student, semester: Semester): Single<MobileDeviceToken> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getToken() return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getToken()
.map { .map {
MobileDeviceToken( MobileDeviceToken(
token = it.token, token = it.token,

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single import io.reactivex.Single
@ -18,11 +19,11 @@ class MobileDeviceRepository @Inject constructor(
private val remote: MobileDeviceRemote private val remote: MobileDeviceRemote
) { ) {
fun getDevices(semester: Semester, forceRefresh: Boolean = false): Single<List<MobileDevice>> { fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<MobileDevice>> {
return local.getDevices(semester).filter { !forceRefresh } return local.getDevices(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getDevices(semester) if (it) remote.getDevices(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getDevices(semester).toSingle(emptyList()) local.getDevices(semester).toSingle(emptyList())
@ -34,18 +35,18 @@ class MobileDeviceRepository @Inject constructor(
).flatMap { local.getDevices(semester).toSingle(emptyList()) } ).flatMap { local.getDevices(semester).toSingle(emptyList()) }
} }
fun unregisterDevice(semester: Semester, device: MobileDevice): Single<Boolean> { fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice): Single<Boolean> {
return ReactiveNetwork.checkInternetConnectivity(settings) return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.unregisterDevice(semester, device) if (it) remote.unregisterDevice(student, semester, device)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
} }
} }
fun getToken(semester: Semester): Single<MobileDeviceToken> { fun getToken(student: Student, semester: Semester): Single<MobileDeviceToken> {
return ReactiveNetwork.checkInternetConnectivity(settings) return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getToken(semester) if (it) remote.getToken(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
} }
} }

View File

@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.note
import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -10,8 +12,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class NoteRemote @Inject constructor(private val sdk: Sdk) { class NoteRemote @Inject constructor(private val sdk: Sdk) {
fun getNotes(semester: Semester): Single<List<Note>> { fun getNotes(student: Student, semester: Semester): Single<List<Note>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getNotes(semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getNotes(semester.semesterId)
.map { notes -> .map { notes ->
notes.map { notes.map {
Note( Note(

View File

@ -23,7 +23,7 @@ class NoteRepository @Inject constructor(
return local.getNotes(student).filter { !forceRefresh } return local.getNotes(student).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getNotes(semester) if (it) remote.getNotes(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getNotes(student).toSingle(emptyList()) local.getNotes(student).toSingle(emptyList())

View File

@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.recipient
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -12,15 +14,15 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
@Singleton @Singleton
class RecipientRemote @Inject constructor(private val sdk: Sdk) { class RecipientRemote @Inject constructor(private val sdk: Sdk) {
fun getRecipients(role: Int, unit: ReportingUnit): Single<List<Recipient>> { fun getRecipients(student: Student, role: Int, unit: ReportingUnit): Single<List<Recipient>> {
return sdk.getRecipients(unit.realId, role) return sdk.init(student).getRecipients(unit.realId, role)
.map { recipients -> .map { recipients ->
recipients.map { it.toRecipient() } recipients.map { it.toRecipient() }
} }
} }
fun getMessageRecipients(message: Message): Single<List<Recipient>> { fun getMessageRecipients(student: Student, message: Message): Single<List<Recipient>> {
return sdk.getMessageRecipients(message.messageId, message.senderId) return sdk.init(student).getMessageRecipients(message.messageId, message.senderId)
.map { recipients -> .map { recipients ->
recipients.map { it.toRecipient() } recipients.map { it.toRecipient() }
} }

View File

@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.recipient
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.SdkHelper
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.ReportingUnit
@ -17,36 +16,31 @@ import javax.inject.Singleton
class RecipientRepository @Inject constructor( class RecipientRepository @Inject constructor(
private val settings: InternetObservingSettings, private val settings: InternetObservingSettings,
private val local: RecipientLocal, private val local: RecipientLocal,
private val remote: RecipientRemote, private val remote: RecipientRemote
private val sdkHelper: SdkHelper
) { ) {
fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single<List<Recipient>> { fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single<List<Recipient>> {
return Single.just(sdkHelper.init(student)) return local.getRecipients(student, role, unit).filter { !forceRefresh }
.flatMap { _ -> .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
local.getRecipients(student, role, unit).filter { !forceRefresh } .flatMap {
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) if (it) remote.getRecipients(student, role, unit)
.flatMap { else Single.error(UnknownHostException())
if (it) remote.getRecipients(role, unit) }.flatMap { new ->
else Single.error(UnknownHostException()) local.getRecipients(student, role, unit).toSingle(emptyList())
}.flatMap { new -> .doOnSuccess { old ->
local.getRecipients(student, role, unit).toSingle(emptyList()) local.deleteRecipients(old.uniqueSubtract(new))
.doOnSuccess { old -> local.saveRecipients(new.uniqueSubtract(old))
local.deleteRecipients(old.uniqueSubtract(new))
local.saveRecipients(new.uniqueSubtract(old))
}
}.flatMap {
local.getRecipients(student, role, unit).toSingle(emptyList())
} }
) }.flatMap {
} local.getRecipients(student, role, unit).toSingle(emptyList())
}
)
} }
fun getMessageRecipients(student: Student, message: Message): Single<List<Recipient>> { fun getMessageRecipients(student: Student, message: Message): Single<List<Recipient>> {
return Single.just(sdkHelper.init(student)) return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { ReactiveNetwork.checkInternetConnectivity(settings) }
.flatMap { .flatMap {
if (it) remote.getMessageRecipients(message) if (it) remote.getMessageRecipients(student, message)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
} }
} }

View File

@ -1,7 +1,9 @@
package io.github.wulkanowy.data.repositories.reportingunit package io.github.wulkanowy.data.repositories.reportingunit
import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -9,8 +11,8 @@ import javax.inject.Singleton
@Singleton @Singleton
class ReportingUnitRemote @Inject constructor(private val sdk: Sdk) { class ReportingUnitRemote @Inject constructor(private val sdk: Sdk) {
fun getReportingUnits(): Single<List<ReportingUnit>> { fun getReportingUnits(student: Student): Single<List<ReportingUnit>> {
return sdk.getReportingUnits().map { return sdk.init(student).getReportingUnits().map {
it.map { unit -> it.map { unit ->
ReportingUnit( ReportingUnit(
studentId = sdk.studentId, studentId = sdk.studentId,

View File

@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.reportingunit
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.SdkHelper
import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
@ -16,41 +15,34 @@ import javax.inject.Singleton
class ReportingUnitRepository @Inject constructor( class ReportingUnitRepository @Inject constructor(
private val settings: InternetObservingSettings, private val settings: InternetObservingSettings,
private val local: ReportingUnitLocal, private val local: ReportingUnitLocal,
private val remote: ReportingUnitRemote, private val remote: ReportingUnitRemote
private val sdkHelper: SdkHelper
) { ) {
fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single<List<ReportingUnit>> { fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single<List<ReportingUnit>> {
return Single.just(sdkHelper.init(student)) return local.getReportingUnits(student).filter { !forceRefresh }
.flatMap { _ -> .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
local.getReportingUnits(student).filter { !forceRefresh } .flatMap {
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) if (it) remote.getReportingUnits(student)
.flatMap { else Single.error(UnknownHostException())
if (it) remote.getReportingUnits() }.flatMap { new ->
else Single.error(UnknownHostException()) local.getReportingUnits(student).toSingle(emptyList())
}.flatMap { new -> .doOnSuccess { old ->
local.getReportingUnits(student).toSingle(emptyList()) local.deleteReportingUnits(old.uniqueSubtract(new))
.doOnSuccess { old -> local.saveReportingUnits(new.uniqueSubtract(old))
local.deleteReportingUnits(old.uniqueSubtract(new)) }
local.saveReportingUnits(new.uniqueSubtract(old)) }.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
} )
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
)
}
} }
fun getReportingUnit(student: Student, unitId: Int): Maybe<ReportingUnit> { fun getReportingUnit(student: Student, unitId: Int): Maybe<ReportingUnit> {
return Maybe.just(sdkHelper.init(student)) return local.getReportingUnit(student, unitId)
.flatMap { _ -> .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
local.getReportingUnit(student, unitId) .flatMap {
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) if (it) getReportingUnits(student, true)
.flatMap { else Single.error(UnknownHostException())
if (it) getReportingUnits(student, true) }.flatMapMaybe {
else Single.error(UnknownHostException()) local.getReportingUnit(student, unitId)
}.flatMapMaybe { }
local.getReportingUnit(student, unitId) )
}
)
}
} }
} }

View File

@ -2,14 +2,17 @@ package io.github.wulkanowy.data.repositories.school
import io.github.wulkanowy.data.db.entities.School import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
class SchoolRemote @Inject constructor(private val sdk: Sdk) { class SchoolRemote @Inject constructor(private val sdk: Sdk) {
fun getSchoolInfo(semester: Semester): Single<School> { fun getSchoolInfo(student: Student, semester: Semester): Single<School> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSchool() return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getSchool()
.map { .map {
School( School(
studentId = semester.studentId, studentId = semester.studentId,

View File

@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.School import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe import io.reactivex.Maybe
import io.reactivex.Single import io.reactivex.Single
import java.net.UnknownHostException import java.net.UnknownHostException
@ -17,11 +18,11 @@ class SchoolRepository @Inject constructor(
private val remote: SchoolRemote private val remote: SchoolRemote
) { ) {
fun getSchoolInfo(semester: Semester, forceRefresh: Boolean = false): Maybe<School> { fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean = false): Maybe<School> {
return local.getSchool(semester).filter { !forceRefresh } return local.getSchool(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getSchoolInfo(semester) if (it) remote.getSchoolInfo(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMapMaybe { new -> }.flatMapMaybe { new ->
local.getSchool(semester) local.getSchool(semester)

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.semester
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -11,7 +12,7 @@ import javax.inject.Singleton
class SemesterRemote @Inject constructor(private val sdk: Sdk) { class SemesterRemote @Inject constructor(private val sdk: Sdk) {
fun getSemesters(student: Student): Single<List<Semester>> { fun getSemesters(student: Student): Single<List<Semester>> {
return sdk.getSemesters().map { semesters -> return sdk.init(student).getSemesters().map { semesters ->
semesters.map { semesters.map {
Semester( Semester(
studentId = student.studentId, studentId = student.studentId,

View File

@ -2,13 +2,12 @@ package io.github.wulkanowy.data.repositories.semester
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.SdkHelper
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.getCurrentOrLast import io.github.wulkanowy.utils.getCurrentOrLast
import io.github.wulkanowy.utils.isCurrent import io.github.wulkanowy.utils.isCurrent
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Maybe
import io.reactivex.Single import io.reactivex.Single
import java.net.UnknownHostException import java.net.UnknownHostException
import javax.inject.Inject import javax.inject.Inject
@ -18,31 +17,28 @@ import javax.inject.Singleton
class SemesterRepository @Inject constructor( class SemesterRepository @Inject constructor(
private val remote: SemesterRemote, private val remote: SemesterRemote,
private val local: SemesterLocal, private val local: SemesterLocal,
private val settings: InternetObservingSettings, private val settings: InternetObservingSettings
private val sdkHelper: SdkHelper
) { ) {
fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false): Single<List<Semester>> { fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false): Single<List<Semester>> {
return Maybe.just(sdkHelper.init(student)) return local.getSemesters(student).filter { !forceRefresh }.filter { semesters ->
.flatMap { when {
local.getSemesters(student).filter { !forceRefresh }.filter { Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API -> semesters.firstOrNull { it.isCurrent }?.diaryId != 0
if (refreshOnNoCurrent) { refreshOnNoCurrent -> semesters.any { semester -> semester.isCurrent }
it.any { semester -> semester.isCurrent } else -> true
} else true
}
} }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) }.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getSemesters(student) if (it) remote.getSemesters(student)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
if (new.isEmpty()) throw IllegalArgumentException("Empty semester list!") if (new.isEmpty()) throw IllegalArgumentException("Empty semester list!")
local.getSemesters(student).toSingle(emptyList()).doOnSuccess { old -> local.getSemesters(student).toSingle(emptyList()).doOnSuccess { old ->
local.deleteSemesters(old.uniqueSubtract(new)) local.deleteSemesters(old.uniqueSubtract(new))
local.saveSemesters(new.uniqueSubtract(old)) local.saveSemesters(new.uniqueSubtract(old))
} }
}.flatMap { local.getSemesters(student).toSingle(emptyList()) }) }.flatMap { local.getSemesters(student).toSingle(emptyList()) })
} }
fun getCurrentSemester(student: Student, forceRefresh: Boolean = false): Single<Semester> { fun getCurrentSemester(student: Student, forceRefresh: Boolean = false): Single<Semester> {

View File

@ -29,10 +29,18 @@ class StudentLocal @Inject constructor(
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> { fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
return studentDb.loadAll() return studentDb.loadAll()
.map { list -> list.map { it.apply { if (decryptPass) password = decrypt(password) } } } .map { list -> list.map { it.apply { if (decryptPass && Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password) } } }
.filter { it.isNotEmpty() } .filter { it.isNotEmpty() }
} }
fun getStudentById(id: Int): Maybe<Student> {
return studentDb.loadById(id).map {
it.apply {
if (Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password)
}
}
}
fun getCurrentStudent(decryptPass: Boolean): Maybe<Student> { fun getCurrentStudent(decryptPass: Boolean): Maybe<Student> {
return studentDb.loadCurrent().map { return studentDb.loadCurrent().map {
it.apply { it.apply {

View File

@ -47,6 +47,12 @@ class StudentRepository @Inject constructor(
return local.getStudents(decryptPass).toSingle(emptyList()) return local.getStudents(decryptPass).toSingle(emptyList())
} }
fun getStudentById(id: Int): Single<Student> {
return local.getStudentById(id)
.switchIfEmpty(Maybe.error(NoCurrentStudentException()))
.toSingle()
}
fun getCurrentStudent(decryptPass: Boolean = true): Single<Student> { fun getCurrentStudent(decryptPass: Boolean = true): Single<Student> {
return local.getCurrentStudent(decryptPass) return local.getCurrentStudent(decryptPass)
.switchIfEmpty(Maybe.error(NoCurrentStudentException())) .switchIfEmpty(Maybe.error(NoCurrentStudentException()))

View File

@ -12,7 +12,7 @@ class SubjectLocal @Inject constructor(private val subjectDao: SubjectDao) {
fun getSubjects(semester: Semester): Maybe<List<Subject>> { fun getSubjects(semester: Semester): Maybe<List<Subject>> {
return subjectDao.loadAll(semester.diaryId, semester.studentId) return subjectDao.loadAll(semester.diaryId, semester.studentId)
.filter { !it.isEmpty() } .filter { it.isNotEmpty() }
} }
fun saveSubjects(subjects: List<Subject>) { fun saveSubjects(subjects: List<Subject>) {

View File

@ -1,8 +1,10 @@
package io.github.wulkanowy.data.repositories.subject package io.github.wulkanowy.data.repositories.subject
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -10,8 +12,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class SubjectRemote @Inject constructor(private val sdk: Sdk) { class SubjectRemote @Inject constructor(private val sdk: Sdk) {
fun getSubjects(semester: Semester): Single<List<Subject>> { fun getSubjects(student: Student, semester: Semester): Single<List<Subject>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSubjects() return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getSubjects()
.map { subjects -> .map { subjects ->
subjects.map { subjects.map {
Subject( Subject(

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.subject
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single import io.reactivex.Single
@ -17,11 +18,11 @@ class SubjectRepository @Inject constructor(
private val remote: SubjectRemote private val remote: SubjectRemote
) { ) {
fun getSubjects(semester: Semester, forceRefresh: Boolean = false): Single<List<Subject>> { fun getSubjects(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<Subject>> {
return local.getSubjects(semester).filter { !forceRefresh } return local.getSubjects(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getSubjects(semester) if (it) remote.getSubjects(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getSubjects(semester) local.getSubjects(semester)

View File

@ -1,8 +1,10 @@
package io.github.wulkanowy.data.repositories.teacher package io.github.wulkanowy.data.repositories.teacher
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -10,8 +12,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class TeacherRemote @Inject constructor(private val sdk: Sdk) { class TeacherRemote @Inject constructor(private val sdk: Sdk) {
fun getTeachers(semester: Semester): Single<List<Teacher>> { fun getTeachers(student: Student, semester: Semester): Single<List<Teacher>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTeachers(semester.semesterId) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getTeachers(semester.semesterId)
.map { teachers -> .map { teachers ->
teachers.map { teachers.map {
Teacher( Teacher(

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.teacher
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single import io.reactivex.Single
@ -17,11 +18,11 @@ class TeacherRepository @Inject constructor(
private val remote: TeacherRemote private val remote: TeacherRemote
) { ) {
fun getTeachers(semester: Semester, forceRefresh: Boolean = false): Single<List<Teacher>> { fun getTeachers(student: Student, semester: Semester, forceRefresh: Boolean = false): Single<List<Teacher>> {
return local.getTeachers(semester).filter { !forceRefresh } return local.getTeachers(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { .flatMap {
if (it) remote.getTeachers(semester) if (it) remote.getTeachers(student, semester)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getTeachers(semester).toSingle(emptyList()) local.getTeachers(semester).toSingle(emptyList())

View File

@ -1,8 +1,10 @@
package io.github.wulkanowy.data.repositories.timetable package io.github.wulkanowy.data.repositories.timetable
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import javax.inject.Inject import javax.inject.Inject
@ -11,8 +13,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class TimetableRemote @Inject constructor(private val sdk: Sdk) { class TimetableRemote @Inject constructor(private val sdk: Sdk) {
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> { fun getTimetable(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Timetable>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTimetable(startDate, endDate) return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getTimetable(startDate, endDate)
.map { lessons -> .map { lessons ->
lessons.map { lessons.map {
Timetable( Timetable(

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.timetable
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
@ -20,11 +21,11 @@ class TimetableRepository @Inject constructor(
private val remote: TimetableRemote private val remote: TimetableRemote
) { ) {
fun getTimetable(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Timetable>> { fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single<List<Timetable>> {
return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) -> return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) ->
local.getTimetable(semester, monday, friday).filter { !forceRefresh } local.getTimetable(semester, monday, friday).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap { .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
if (it) remote.getTimetable(semester, monday, friday) if (it) remote.getTimetable(student, semester, monday, friday)
else Single.error(UnknownHostException()) else Single.error(UnknownHostException())
}.flatMap { new -> }.flatMap { new ->
local.getTimetable(semester, monday, friday) local.getTimetable(semester, monday, friday)

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.di
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import io.github.wulkanowy.di.scopes.PerActivity import io.github.wulkanowy.di.scopes.PerActivity
import io.github.wulkanowy.ui.base.ErrorDialog
import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.login.LoginModule import io.github.wulkanowy.ui.modules.login.LoginModule
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity
@ -18,6 +19,9 @@ import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider
@Module @Module
internal abstract class BindingModule { internal abstract class BindingModule {
@ContributesAndroidInjector
abstract fun bindErrorDialog(): ErrorDialog
@PerActivity @PerActivity
@ContributesAndroidInjector @ContributesAndroidInjector
abstract fun bindSplashActivity(): SplashActivity abstract fun bindSplashActivity(): SplashActivity

View File

@ -1,7 +1,6 @@
package io.github.wulkanowy.services.sync package io.github.wulkanowy.services.sync
import android.content.Context import android.content.Context
import android.os.Build.VERSION_CODES.LOLLIPOP
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.BigTextStyle import androidx.core.app.NotificationCompat.BigTextStyle
import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT
@ -17,9 +16,9 @@ import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.sdk.exception.FeatureDisabledException import io.github.wulkanowy.sdk.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.services.sync.channels.DebugChannel import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.works.Work import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.getCompatColor import io.github.wulkanowy.utils.getCompatColor
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Single import io.reactivex.Single
@ -33,8 +32,7 @@ class SyncWorker @AssistedInject constructor(
private val semesterRepository: SemesterRepository, private val semesterRepository: SemesterRepository,
private val works: Set<@JvmSuppressWildcards Work>, private val works: Set<@JvmSuppressWildcards Work>,
private val preferencesRepository: PreferencesRepository, private val preferencesRepository: PreferencesRepository,
private val notificationManager: NotificationManagerCompat, private val notificationManager: NotificationManagerCompat
private val appInfo: AppInfo
) : RxWorker(appContext, workerParameters) { ) : RxWorker(appContext, workerParameters) {
override fun createWork(): Single<Result> { override fun createWork(): Single<Result> {
@ -47,6 +45,10 @@ class SyncWorker @AssistedInject constructor(
.flatMapCompletable { semester -> .flatMapCompletable { semester ->
Completable.mergeDelayError(works.map { work -> Completable.mergeDelayError(works.map { work ->
work.create(student, semester) work.create(student, semester)
.onErrorResumeNext {
if (it is FeatureDisabledException || it is FeatureNotAvailableException) Completable.complete()
else Completable.error(it)
}
.doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") } .doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") }
.doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") } .doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") }
.doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") } .doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") }
@ -57,11 +59,11 @@ class SyncWorker @AssistedInject constructor(
.onErrorReturn { .onErrorReturn {
Timber.e(it, "There was an error during synchronization") Timber.e(it, "There was an error during synchronization")
when { when {
it is FeatureDisabledException -> Result.success()
inputData.getBoolean("one_time", false) -> { inputData.getBoolean("one_time", false) -> {
Result.failure(Data.Builder() Result.failure(Data.Builder()
.putString("error", it.toString()) .putString("error", it.toString())
.build()) .build()
)
} }
else -> Result.retry() else -> Result.retry()
} }

View File

@ -11,7 +11,7 @@ class AttendanceSummaryWork @Inject constructor(
) : Work { ) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return attendanceSummaryRepository.getAttendanceSummary(semester, -1, true).ignoreElement() return attendanceSummaryRepository.getAttendanceSummary(student, semester, -1, true).ignoreElement()
} }
} }

View File

@ -12,7 +12,7 @@ import javax.inject.Inject
class AttendanceWork @Inject constructor(private val attendanceRepository: AttendanceRepository) : Work { class AttendanceWork @Inject constructor(private val attendanceRepository: AttendanceRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return attendanceRepository.getAttendance(semester, now().monday, now().friday, true) return attendanceRepository.getAttendance(student, semester, now().monday, now().friday, true)
.ignoreElement() .ignoreElement()
} }
} }

View File

@ -14,7 +14,7 @@ class CompletedLessonWork @Inject constructor(
) : Work { ) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return completedLessonsRepository.getCompletedLessons(semester, now().monday, now().friday, true) return completedLessonsRepository.getCompletedLessons(student, semester, now().monday, now().friday, true)
.ignoreElement() .ignoreElement()
} }
} }

View File

@ -12,6 +12,6 @@ import javax.inject.Inject
class ExamWork @Inject constructor(private val examRepository: ExamRepository) : Work { class ExamWork @Inject constructor(private val examRepository: ExamRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return examRepository.getExams(semester, now().monday, now().friday, true).ignoreElement() return examRepository.getExams(student, semester, now().monday, now().friday, true).ignoreElement()
} }
} }

View File

@ -9,7 +9,7 @@ import javax.inject.Inject
class GradeStatisticsWork @Inject constructor(private val gradeStatisticsRepository: GradeStatisticsRepository) : Work { class GradeStatisticsWork @Inject constructor(private val gradeStatisticsRepository: GradeStatisticsRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return gradeStatisticsRepository.getGradesStatistics(semester, "Wszystkie", false, true) return gradeStatisticsRepository.getGradesStatistics(student, semester, "Wszystkie", false, true)
.ignoreElement() .ignoreElement()
} }
} }

View File

@ -9,6 +9,6 @@ import javax.inject.Inject
class GradeSummaryWork @Inject constructor(private val gradeSummaryRepository: GradeSummaryRepository) : Work { class GradeSummaryWork @Inject constructor(private val gradeSummaryRepository: GradeSummaryRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return gradeSummaryRepository.getGradesSummary(semester, true).ignoreElement() return gradeSummaryRepository.getGradesSummary(student, semester, true).ignoreElement()
} }
} }

View File

@ -12,6 +12,6 @@ import javax.inject.Inject
class HomeworkWork @Inject constructor(private val homeworkRepository: HomeworkRepository) : Work { class HomeworkWork @Inject constructor(private val homeworkRepository: HomeworkRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return homeworkRepository.getHomework(semester, now().monday, now().friday, true).ignoreElement() return homeworkRepository.getHomework(student, semester, now().monday, now().friday, true).ignoreElement()
} }
} }

View File

@ -9,6 +9,6 @@ import javax.inject.Inject
class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work { class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return teacherRepository.getTeachers(semester, true).ignoreElement() return teacherRepository.getTeachers(student, semester, true).ignoreElement()
} }
} }

View File

@ -12,7 +12,7 @@ import javax.inject.Inject
class TimetableWork @Inject constructor(private val timetableRepository: TimetableRepository) : Work { class TimetableWork @Inject constructor(private val timetableRepository: TimetableRepository) : Work {
override fun create(student: Student, semester: Semester): Completable { override fun create(student: Student, semester: Semester): Completable {
return timetableRepository.getTimetable(semester, now().monday, now().friday, true) return timetableRepository.getTimetable(student, semester, now().monday, now().friday, true)
.ignoreElement() .ignoreElement()
} }
} }

View File

@ -6,19 +6,33 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.HorizontalScrollView
import android.widget.Toast import android.widget.Toast
import android.widget.Toast.LENGTH_LONG import android.widget.Toast.LENGTH_LONG
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.fragment.app.DialogFragment
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.getString
import io.github.wulkanowy.utils.openEmailClient
import io.github.wulkanowy.utils.openInternetBrowser
import kotlinx.android.synthetic.main.dialog_error.* import kotlinx.android.synthetic.main.dialog_error.*
import java.io.InterruptedIOException
import java.io.PrintWriter import java.io.PrintWriter
import java.io.StringWriter import java.io.StringWriter
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.inject.Inject
class ErrorDialog : DialogFragment() { class ErrorDialog : BaseDialogFragment() {
private lateinit var error: Throwable private lateinit var error: Throwable
@Inject
lateinit var appInfo: AppInfo
companion object { companion object {
private const val ARGUMENT_KEY = "Data" private const val ARGUMENT_KEY = "Data"
@ -49,6 +63,9 @@ class ErrorDialog : DialogFragment() {
} }
errorDialogContent.text = stringWriter.toString() errorDialogContent.text = stringWriter.toString()
with(errorDialogHorizontalScroll) {
post { fullScroll(HorizontalScrollView.FOCUS_LEFT) }
}
errorDialogCopy.setOnClickListener { errorDialogCopy.setOnClickListener {
val clip = ClipData.newPlainText("wulkanowy", stringWriter.toString()) val clip = ClipData.newPlainText("wulkanowy", stringWriter.toString())
activity?.getSystemService<ClipboardManager>()?.setPrimaryClip(clip) activity?.getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
@ -56,6 +73,30 @@ class ErrorDialog : DialogFragment() {
Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show() Toast.makeText(context, R.string.all_copied, LENGTH_LONG).show()
} }
errorDialogCancel.setOnClickListener { dismiss() } errorDialogCancel.setOnClickListener { dismiss() }
errorDialogReport.setOnClickListener { openEmailClient(stringWriter.toString()) }
errorDialogMessage.text = resources.getString(error)
errorDialogReport.isEnabled = when (error) {
is UnknownHostException,
is InterruptedIOException,
is SocketTimeoutException,
is ServiceUnavailableException,
is FeatureDisabledException,
is FeatureNotAvailableException -> false
else -> true
}
}
private fun openEmailClient(content: String) {
requireContext().openEmailClient(
chooserTitle = getString(R.string.about_feedback),
email = "wulkanowyinc@gmail.com",
subject = "Zgłoszenie błędu",
body = requireContext().getString(R.string.about_feedback_template,
"${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName
) + "\n" + content,
onActivityNotFound = {
requireContext().openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage)
}
)
} }
} }

View File

@ -2,17 +2,11 @@ package io.github.wulkanowy.ui.base
import android.content.res.Resources import android.content.res.Resources
import com.chuckerteam.chucker.api.ChuckerCollector import com.chuckerteam.chucker.api.ChuckerCollector
import io.github.wulkanowy.R
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.sdk.exception.BadCredentialsException import io.github.wulkanowy.sdk.exception.BadCredentialsException
import io.github.wulkanowy.sdk.exception.FeatureDisabledException import io.github.wulkanowy.utils.getString
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.exception.NotLoggedInException
import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
import io.github.wulkanowy.utils.security.ScramblerException import io.github.wulkanowy.utils.security.ScramblerException
import timber.log.Timber import timber.log.Timber
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.inject.Inject import javax.inject.Inject
open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckerCollector: ChuckerCollector) { open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckerCollector: ChuckerCollector) {
@ -30,18 +24,10 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources,
} }
protected open fun proceed(error: Throwable) { protected open fun proceed(error: Throwable) {
resources.run { when (error) {
when (error) { is ScramblerException, is BadCredentialsException -> onSessionExpired()
is UnknownHostException -> showErrorMessage(getString(R.string.error_no_internet), error) is NoCurrentStudentException -> onNoCurrentStudent()
is SocketTimeoutException -> showErrorMessage(getString(R.string.error_timeout), error) else -> showErrorMessage(resources.getString(error), error)
is NotLoggedInException -> showErrorMessage(getString(R.string.error_login_failed), error)
is ServiceUnavailableException -> showErrorMessage(getString(R.string.error_service_unavailable), error)
is FeatureDisabledException -> showErrorMessage(getString(R.string.error_feature_disabled), error)
is ScramblerException, is BadCredentialsException -> onSessionExpired()
is NoCurrentStudentException -> onNoCurrentStudent()
is FeatureNotAvailableException -> showErrorMessage(getString(R.string.error_feature_not_available), error)
else -> showErrorMessage(getString(R.string.error_unknown), error)
}
} }
} }

View File

@ -188,13 +188,16 @@ class AttendancePresenter @Inject constructor(
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.delay(200, MILLISECONDS) .flatMap { student ->
.flatMap { semesterRepository.getCurrentSemester(it) } semesterRepository.getCurrentSemester(student).flatMap { semester ->
.flatMap { attendanceRepository.getAttendance(it, date, date, forceRefresh) } attendanceRepository.getAttendance(student, semester, date, date, forceRefresh)
}
}
.map { list -> .map { list ->
if (prefRepository.isShowPresent) list if (prefRepository.isShowPresent) list
else list.filter { !it.presence } else list.filter { !it.presence }
} }
.delay(200, MILLISECONDS)
.map { items -> items.map { AttendanceItem(it) } } .map { items -> items.map { AttendanceItem(it) } }
.map { items -> items.sortedBy { it.attendance.number } } .map { items -> items.sortedBy { it.attendance.number } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
@ -228,9 +231,12 @@ class AttendancePresenter @Inject constructor(
Timber.i("Excusing absence started") Timber.i("Excusing absence started")
disposable.apply { disposable.apply {
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.flatMap { student ->
semesterRepository.getCurrentSemester(student).flatMap { semester ->
attendanceRepository.excuseForAbsence(student, semester, toExcuseList, reason)
}
}
.delay(200, MILLISECONDS) .delay(200, MILLISECONDS)
.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { attendanceRepository.excuseForAbsence(it, toExcuseList, reason) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doOnSubscribe { .doOnSubscribe {

View File

@ -83,10 +83,13 @@ class AttendanceSummaryPresenter @Inject constructor(
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.delay(200, MILLISECONDS) .flatMap { student ->
.flatMap { semesterRepository.getCurrentSemester(it) } semesterRepository.getCurrentSemester(student).flatMap {
.flatMap { attendanceSummaryRepository.getAttendanceSummary(it, subjectId, forceRefresh) } attendanceSummaryRepository.getAttendanceSummary(student, it, subjectId, forceRefresh)
}
}
.map { createAttendanceSummaryItems(it) to AttendanceSummaryScrollableHeader(formatPercentage(it.calculatePercentage())) } .map { createAttendanceSummaryItems(it) to AttendanceSummaryScrollableHeader(formatPercentage(it.calculatePercentage())) }
.delay(200, MILLISECONDS)
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doFinally { .doFinally {
@ -126,8 +129,11 @@ class AttendanceSummaryPresenter @Inject constructor(
private fun loadSubjects() { private fun loadSubjects() {
Timber.i("Loading attendance summary subjects started") Timber.i("Loading attendance summary subjects started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
.flatMap { subjectRepository.getSubjects(it) } semesterRepository.getCurrentSemester(student).flatMap { semester ->
subjectRepository.getSubjects(student, semester)
}
}
.doOnSuccess { subjects = it } .doOnSuccess { subjects = it }
.map { ArrayList(it.map { subject -> subject.name }) } .map { ArrayList(it.map { subject -> subject.name }) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -112,9 +112,12 @@ class ExamPresenter @Inject constructor(
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.flatMap { student ->
semesterRepository.getCurrentSemester(student).flatMap { semester ->
examRepository.getExams(student, semester, currentDate.monday, currentDate.friday, forceRefresh)
}
}
.delay(200, MILLISECONDS) .delay(200, MILLISECONDS)
.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { examRepository.getExams(it, currentDate.monday, currentDate.friday, forceRefresh) }
.map { it.groupBy { exam -> exam.date }.toSortedMap() } .map { it.groupBy { exam -> exam.date }.toSortedMap() }
.map { createExamItems(it) } .map { createExamItems(it) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -34,7 +34,7 @@ class GradeAverageProvider @Inject constructor(
val selectedSemester = semesters.single { it.semesterId == semesterId } val selectedSemester = semesters.single { it.semesterId == semesterId }
val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 }
return getAverageFromGradeSummary(selectedSemester, forceRefresh) return getAverageFromGradeSummary(student, selectedSemester, forceRefresh)
.switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh)
.flatMap { firstGrades -> .flatMap { firstGrades ->
if (selectedSemester == firstSemester) Single.just(firstGrades) if (selectedSemester == firstSemester) Single.just(firstGrades)
@ -52,7 +52,7 @@ class GradeAverageProvider @Inject constructor(
private fun getOnlyOneSemesterAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Single<List<Triple<String, Double, String>>> { private fun getOnlyOneSemesterAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Single<List<Triple<String, Double, String>>> {
val selectedSemester = semesters.single { it.semesterId == semesterId } val selectedSemester = semesters.single { it.semesterId == semesterId }
return getAverageFromGradeSummary(selectedSemester, forceRefresh) return getAverageFromGradeSummary(student, selectedSemester, forceRefresh)
.switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh)
.map { grades -> .map { grades ->
grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it } grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it }
@ -61,8 +61,8 @@ class GradeAverageProvider @Inject constructor(
}) })
} }
private fun getAverageFromGradeSummary(selectedSemester: Semester, forceRefresh: Boolean): Maybe<List<Triple<String, Double, String>>> { private fun getAverageFromGradeSummary(student: Student, selectedSemester: Semester, forceRefresh: Boolean): Maybe<List<Triple<String, Double, String>>> {
return gradeSummaryRepository.getGradesSummary(selectedSemester, forceRefresh) return gradeSummaryRepository.getGradesSummary(student, selectedSemester, forceRefresh)
.toMaybe() .toMaybe()
.flatMap { .flatMap {
if (it.any { summary -> summary.average != .0 }) { if (it.any { summary -> summary.average != .0 }) {

View File

@ -48,7 +48,6 @@ class GradeStatisticsPresenter @Inject constructor(
loadDataByType(semesterId, currentSubjectName, currentType, forceRefresh) loadDataByType(semesterId, currentSubjectName, currentType, forceRefresh)
} }
fun onParentViewReselected() { fun onParentViewReselected() {
view?.run { view?.run {
if (!isViewEmpty) resetView() if (!isViewEmpty) resetView()
@ -118,8 +117,11 @@ class GradeStatisticsPresenter @Inject constructor(
private fun loadSubjects() { private fun loadSubjects() {
Timber.i("Loading grade stats subjects started") Timber.i("Loading grade stats subjects started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
.flatMap { subjectRepository.getSubjects(it) } semesterRepository.getCurrentSemester(student).flatMap { semester ->
subjectRepository.getSubjects(student, semester)
}
}
.doOnSuccess { subjects = it } .doOnSuccess { subjects = it }
.map { ArrayList(it.map { subject -> subject.name }) } .map { ArrayList(it.map { subject -> subject.name }) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
@ -131,7 +133,7 @@ class GradeStatisticsPresenter @Inject constructor(
showSubjects(true) showSubjects(true)
} }
}, { }, {
Timber.e("Loading grade stats subjects result: An exception occurred") Timber.i("Loading grade stats subjects result: An exception occurred")
errorHandler.dispatch(it) errorHandler.dispatch(it)
}) })
) )
@ -146,14 +148,15 @@ class GradeStatisticsPresenter @Inject constructor(
private fun loadData(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean) { private fun loadData(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean) {
Timber.i("Loading grade stats data started") Timber.i("Loading grade stats data started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getSemesters(it) } .flatMap { student ->
.flatMap { semesterRepository.getSemesters(student).flatMap { semesters ->
val semester = it.first { item -> item.semesterId == semesterId } val semester = semesters.first { item -> item.semesterId == semesterId }
when (type) { when (type) {
ViewType.SEMESTER -> gradeStatisticsRepository.getGradesStatistics(semester, subjectName, true, forceRefresh) ViewType.SEMESTER -> gradeStatisticsRepository.getGradesStatistics(student, semester, subjectName, true, forceRefresh)
ViewType.PARTIAL -> gradeStatisticsRepository.getGradesStatistics(semester, subjectName, false, forceRefresh) ViewType.PARTIAL -> gradeStatisticsRepository.getGradesStatistics(student, semester, subjectName, false, forceRefresh)
ViewType.POINTS -> gradeStatisticsRepository.getGradesPointsStatistics(semester, subjectName, forceRefresh) ViewType.POINTS -> gradeStatisticsRepository.getGradesPointsStatistics(student, semester, subjectName, forceRefresh)
}
} }
} }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
@ -176,7 +179,7 @@ class GradeStatisticsPresenter @Inject constructor(
} }
analytics.logEvent("load_grade_statistics", "items" to it.size, "force_refresh" to forceRefresh) analytics.logEvent("load_grade_statistics", "items" to it.size, "force_refresh" to forceRefresh)
}) { }) {
Timber.e("Loading grade stats result: An exception occurred") Timber.i("Loading grade stats result: An exception occurred")
errorHandler.dispatch(it) errorHandler.dispatch(it)
}) })
} }

View File

@ -38,7 +38,7 @@ class GradeSummaryPresenter @Inject constructor(
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } } .flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } }
.flatMap { (student, semesters) -> .flatMap { (student, semesters) ->
gradeSummaryRepository.getGradesSummary(semesters.first { it.semesterId == semesterId }, forceRefresh) gradeSummaryRepository.getGradesSummary(student, semesters.first { it.semesterId == semesterId }, forceRefresh)
.map { it.sortedBy { subject -> subject.subject } } .map { it.sortedBy { subject -> subject.subject } }
.flatMap { gradesSummary -> .flatMap { gradesSummary ->
averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh) averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh)

View File

@ -105,9 +105,12 @@ class HomeworkPresenter @Inject constructor(
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.flatMap { student ->
semesterRepository.getCurrentSemester(student).flatMap { semester ->
homeworkRepository.getHomework(student, semester, currentDate, currentDate, forceRefresh)
}
}
.delay(200, TimeUnit.MILLISECONDS) .delay(200, TimeUnit.MILLISECONDS)
.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { homeworkRepository.getHomework(it, currentDate, currentDate, forceRefresh) }
.map { it.groupBy { homework -> homework.date }.toSortedMap() } .map { it.groupBy { homework -> homework.date }.toSortedMap() }
.map { createHomeworkItem(it) } .map { createHomeworkItem(it) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -0,0 +1,84 @@
package io.github.wulkanowy.ui.modules.homework.details
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.utils.toFormattedString
import kotlinx.android.synthetic.main.item_homework_dialog_attachment.view.*
import kotlinx.android.synthetic.main.item_homework_dialog_details.view.*
import javax.inject.Inject
class HomeworkDetailsAdapter @Inject constructor() :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private enum class ViewType(val id: Int) {
DETAILS(1),
ATTACHMENTS_HEADER(2),
ATTACHMENT(3)
}
private var attachments = emptyList<Pair<String, String>>()
var homework: Homework? = null
set(value) {
field = value
attachments = value?.attachments.orEmpty()
}
var onAttachmentClickListener: (url: String) -> Unit = {}
override fun getItemCount() = 1 + if (attachments.isNotEmpty()) attachments.size + 1 else 0
override fun getItemViewType(position: Int) = when (position) {
0 -> ViewType.DETAILS.id
1 -> ViewType.ATTACHMENTS_HEADER.id
else -> ViewType.ATTACHMENT.id
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
ViewType.ATTACHMENTS_HEADER.id -> AttachmentsHeaderViewHolder(inflater.inflate(R.layout.item_homework_dialog_attachments_header, parent, false))
ViewType.ATTACHMENT.id -> AttachmentViewHolder(inflater.inflate(R.layout.item_homework_dialog_attachment, parent, false))
else -> DetailsViewHolder(inflater.inflate(R.layout.item_homework_dialog_details, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is DetailsViewHolder -> bindDetailsViewHolder(holder)
is AttachmentViewHolder -> bindAttachmentViewHolder(holder, position - 2)
}
}
private fun bindDetailsViewHolder(holder: DetailsViewHolder) {
with(holder.view) {
homeworkDialogDate.text = homework?.date?.toFormattedString()
homeworkDialogEntryDate.text = homework?.entryDate?.toFormattedString()
homeworkDialogSubject.text = homework?.subject
homeworkDialogTeacher.text = homework?.teacher
homeworkDialogContent.text = homework?.content
}
}
private fun bindAttachmentViewHolder(holder: AttachmentViewHolder, position: Int) {
val item = attachments[position]
with(holder.view) {
homeworkDialogAttachment.text = item.second
setOnClickListener {
onAttachmentClickListener(item.first)
}
}
}
class DetailsViewHolder(val view: View) : RecyclerView.ViewHolder(view)
class AttachmentsHeaderViewHolder(val view: View) : RecyclerView.ViewHolder(view)
class AttachmentViewHolder(val view: View) : RecyclerView.ViewHolder(view)
}

View File

@ -2,16 +2,15 @@ package io.github.wulkanowy.ui.modules.homework.details
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.text.HtmlCompat import androidx.recyclerview.widget.LinearLayoutManager
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.ui.base.BaseDialogFragment import io.github.wulkanowy.ui.base.BaseDialogFragment
import io.github.wulkanowy.ui.modules.homework.HomeworkFragment import io.github.wulkanowy.ui.modules.homework.HomeworkFragment
import io.github.wulkanowy.utils.toFormattedString import io.github.wulkanowy.utils.openInternetBrowser
import kotlinx.android.synthetic.main.dialog_homework.* import kotlinx.android.synthetic.main.dialog_homework.*
import javax.inject.Inject import javax.inject.Inject
@ -20,6 +19,9 @@ class HomeworkDetailsDialog : BaseDialogFragment(), HomeworkDetailsView {
@Inject @Inject
lateinit var presenter: HomeworkDetailsPresenter lateinit var presenter: HomeworkDetailsPresenter
@Inject
lateinit var detailsAdapter: HomeworkDetailsAdapter
private lateinit var homework: Homework private lateinit var homework: Homework
companion object { companion object {
@ -51,20 +53,17 @@ class HomeworkDetailsDialog : BaseDialogFragment(), HomeworkDetailsView {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun initView() { override fun initView() {
homeworkDialogDate.text = homework.date.toFormattedString()
homeworkDialogEntryDate.text = homework.entryDate.toFormattedString()
homeworkDialogSubject.text = homework.subject
homeworkDialogTeacher.text = homework.teacher
homeworkDialogContent.movementMethod = LinkMovementMethod.getInstance()
homeworkDialogContent.text = homework.content
homeworkDialogAttachments.movementMethod = LinkMovementMethod.getInstance()
homeworkDialogAttachments.text = HtmlCompat.fromHtml(homework.attachments.joinToString("<br>") {
"<a href='${it.first}'>${it.second}</a>"
}, HtmlCompat.FROM_HTML_MODE_COMPACT).ifBlank { getString(R.string.all_no_data) }
homeworkDialogRead.text = view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done) homeworkDialogRead.text = view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done)
homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) } homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) }
homeworkDialogClose.setOnClickListener { dismiss() } homeworkDialogClose.setOnClickListener { dismiss() }
with(homeworkDialogRecycler) {
layoutManager = LinearLayoutManager(context)
adapter = detailsAdapter.apply {
onAttachmentClickListener = { context.openInternetBrowser(it, ::showMessage) }
homework = this@HomeworkDetailsDialog.homework
}
}
} }
override fun updateMarkAsDoneLabel(isDone: Boolean) { override fun updateMarkAsDoneLabel(isDone: Boolean) {

View File

@ -7,7 +7,6 @@ import android.view.View
import android.view.View.GONE import android.view.View.GONE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
@ -46,9 +45,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
override val formHostSymbol: String override val formHostSymbol: String
get() = hostSymbols.getOrNull(hostKeys.indexOf(loginFormHost.text.toString())).orEmpty() get() = hostSymbols.getOrNull(hostKeys.indexOf(loginFormHost.text.toString())).orEmpty()
override val formSymbolValue: String
get() = loginFormSymbol.text.toString()
override val nicknameLabel: String override val nicknameLabel: String
get() = getString(R.string.login_nickname_hint) get() = getString(R.string.login_nickname_hint)
@ -77,7 +73,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
loginFormUsername.doOnTextChanged { _, _, _, _ -> presenter.onUsernameTextChanged() } loginFormUsername.doOnTextChanged { _, _, _, _ -> presenter.onUsernameTextChanged() }
loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() } loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() }
loginFormSymbol.doOnTextChanged { _, _, _, _ -> presenter.onSymbolTextChanged() }
loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() } loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() }
loginFormSignIn.setOnClickListener { presenter.onSignInClick() } loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
loginFormAdvancedButton.setOnClickListener { presenter.onAdvancedLoginClick() } loginFormAdvancedButton.setOnClickListener { presenter.onAdvancedLoginClick() }
@ -86,9 +81,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
loginFormContactEmail.setOnClickListener { presenter.onEmailClick() } loginFormContactEmail.setOnClickListener { presenter.onEmailClick() }
loginFormRecoverLink.setOnClickListener { presenter.onRecoverClick() } loginFormRecoverLink.setOnClickListener { presenter.onRecoverClick() }
loginFormPass.setOnEditorDoneSignIn { loginFormSignIn.callOnClick() } loginFormPass.setOnEditorDoneSignIn { loginFormSignIn.callOnClick() }
loginFormSymbol.setOnEditorDoneSignIn { loginFormSignIn.callOnClick() }
loginFormSymbol.setAdapter(ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values)))
with(loginFormHost) { with(loginFormHost) {
setText(hostKeys.getOrNull(0).orEmpty()) setText(hostKeys.getOrNull(0).orEmpty())
@ -102,18 +94,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
loginFormPass.setText(pass) loginFormPass.setText(pass)
} }
override fun setSymbol(symbol: String) {
loginFormSymbol.setText(symbol)
}
override fun setUsernameLabel(label: String) { override fun setUsernameLabel(label: String) {
loginFormUsernameLayout.hint = label loginFormUsernameLayout.hint = label
} }
override fun showSymbol(show: Boolean) {
loginFormSymbolLayout.visibility = if (show) VISIBLE else GONE
}
override fun setErrorUsernameRequired() { override fun setErrorUsernameRequired() {
with(loginFormUsernameLayout) { with(loginFormUsernameLayout) {
requestFocus() requestFocus()
@ -135,13 +119,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
} }
} }
override fun setErrorSymbolRequired(focus: Boolean) {
with(loginFormSymbolLayout) {
if (focus) requestFocus()
error = getString(R.string.login_symbol_helper)
}
}
override fun setErrorPassRequired(focus: Boolean) { override fun setErrorPassRequired(focus: Boolean) {
with(loginFormPassLayout) { with(loginFormPassLayout) {
if (focus) requestFocus() if (focus) requestFocus()
@ -171,10 +148,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
loginFormPassLayout.error = null loginFormPassLayout.error = null
} }
override fun clearSymbolError() {
loginFormSymbolLayout.error = null
}
override fun showSoftKeyboard() { override fun showSoftKeyboard() {
activity?.showSoftInput() activity?.showSoftInput()
} }
@ -227,10 +200,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
with(presenter) { presenter.updateUsernameLabel()
updateUsernameLabel()
updateSymbolInputVisibility()
}
} }
override fun openEmail(lastError: String) { override fun openEmail(lastError: String) {
@ -242,7 +212,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
"${appInfo.systemManufacturer} ${appInfo.systemModel}", "${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(), appInfo.systemVersion.toString(),
appInfo.versionName, appInfo.versionName,
"$formHostValue/$formSymbolValue", "$formHostValue/$formHostSymbol",
lastError lastError
) )
) )

View File

@ -48,9 +48,7 @@ class LoginFormPresenter @Inject constructor(
if (formHostValue.contains("fakelog")) { if (formHostValue.contains("fakelog")) {
setCredentials("jan@fakelog.cf", "jan123") setCredentials("jan@fakelog.cf", "jan123")
} }
setSymbol(formHostSymbol)
updateUsernameLabel() updateUsernameLabel()
updateSymbolInputVisibility()
} }
} }
@ -60,12 +58,6 @@ class LoginFormPresenter @Inject constructor(
} }
} }
fun updateSymbolInputVisibility() {
view?.run {
showSymbol("adfs" in formHostValue)
}
}
fun onPassTextChanged() { fun onPassTextChanged() {
view?.clearPassError() view?.clearPassError()
} }
@ -74,17 +66,13 @@ class LoginFormPresenter @Inject constructor(
view?.clearUsernameError() view?.clearUsernameError()
} }
fun onSymbolTextChanged() {
view?.clearSymbolError()
}
fun onSignInClick() { fun onSignInClick() {
val email = view?.formUsernameValue.orEmpty().trim() val email = view?.formUsernameValue.orEmpty().trim()
val password = view?.formPassValue.orEmpty().trim() val password = view?.formPassValue.orEmpty().trim()
val host = view?.formHostValue.orEmpty().trim() val host = view?.formHostValue.orEmpty().trim()
val symbol = view?.formSymbolValue.orEmpty().trim() val symbol = view?.formHostSymbol.orEmpty().trim()
if (!validateCredentials(email, password, host, symbol)) return if (!validateCredentials(email, password, host)) return
disposable.add(studentRepository.getStudentsScrapper(email, password, host, symbol) disposable.add(studentRepository.getStudentsScrapper(email, password, host, symbol)
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
@ -128,7 +116,7 @@ class LoginFormPresenter @Inject constructor(
view?.onRecoverClick() view?.onRecoverClick()
} }
private fun validateCredentials(login: String, password: String, host: String, symbol: String): Boolean { private fun validateCredentials(login: String, password: String, host: String): Boolean {
var isCorrect = true var isCorrect = true
if (login.isEmpty()) { if (login.isEmpty()) {
@ -156,11 +144,6 @@ class LoginFormPresenter @Inject constructor(
isCorrect = false isCorrect = false
} }
if ("standard" !in host && symbol.isBlank()) {
view?.setErrorSymbolRequired(focus = isCorrect)
isCorrect = false
}
return isCorrect return isCorrect
} }
} }

View File

@ -15,28 +15,20 @@ interface LoginFormView : BaseView {
val formHostSymbol: String val formHostSymbol: String
val formSymbolValue: String
val nicknameLabel: String val nicknameLabel: String
val emailLabel: String val emailLabel: String
fun setCredentials(username: String, pass: String) fun setCredentials(username: String, pass: String)
fun setSymbol(symbol: String)
fun setUsernameLabel(label: String) fun setUsernameLabel(label: String)
fun showSymbol(show: Boolean)
fun setErrorUsernameRequired() fun setErrorUsernameRequired()
fun setErrorLoginRequired() fun setErrorLoginRequired()
fun setErrorEmailRequired() fun setErrorEmailRequired()
fun setErrorSymbolRequired(focus: Boolean)
fun setErrorPassRequired(focus: Boolean) fun setErrorPassRequired(focus: Boolean)
fun setErrorPassInvalid(focus: Boolean) fun setErrorPassInvalid(focus: Boolean)
@ -47,8 +39,6 @@ interface LoginFormView : BaseView {
fun clearPassError() fun clearPassError()
fun clearSymbolError()
fun showSoftKeyboard() fun showSoftKeyboard()
fun hideSoftKeyboard() fun hideSoftKeyboard()

View File

@ -11,7 +11,6 @@ import android.view.ViewGroup
import android.webkit.JavascriptInterface import android.webkit.JavascriptInterface
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import android.widget.ArrayAdapter
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.base.BaseFragment
@ -35,15 +34,17 @@ class LoginRecoverFragment : BaseFragment(), LoginRecoverView {
private lateinit var hostValues: Array<String> private lateinit var hostValues: Array<String>
private lateinit var hostSymbols: Array<String>
override val recoverHostValue: String override val recoverHostValue: String
get() = hostValues.getOrNull(hostKeys.indexOf(loginRecoverHost.text.toString())).orEmpty() get() = hostValues.getOrNull(hostKeys.indexOf(loginRecoverHost.text.toString())).orEmpty()
override val formHostSymbol: String
get() = hostSymbols.getOrNull(hostKeys.indexOf(loginRecoverHost.text.toString())).orEmpty()
override val recoverNameValue: String override val recoverNameValue: String
get() = loginRecoverName.text.toString().trim() get() = loginRecoverName.text.toString().trim()
override val recoverSymbolValue: String
get() = loginRecoverSymbol.text.toString().trim()
override val emailHintString: String override val emailHintString: String
get() = getString(R.string.login_email_hint) get() = getString(R.string.login_email_hint)
@ -66,17 +67,15 @@ class LoginRecoverFragment : BaseFragment(), LoginRecoverView {
loginRecoverWebView.setBackgroundColor(Color.TRANSPARENT) loginRecoverWebView.setBackgroundColor(Color.TRANSPARENT)
hostKeys = resources.getStringArray(R.array.hosts_keys) hostKeys = resources.getStringArray(R.array.hosts_keys)
hostValues = resources.getStringArray(R.array.hosts_values) hostValues = resources.getStringArray(R.array.hosts_values)
hostSymbols = resources.getStringArray(R.array.hosts_symbols)
loginRecoverName.doOnTextChanged { _, _, _, _ -> presenter.onNameTextChanged() } loginRecoverName.doOnTextChanged { _, _, _, _ -> presenter.onNameTextChanged() }
loginRecoverSymbol.doOnTextChanged { _, _, _, _ -> presenter.onSymbolTextChanged() }
loginRecoverHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() } loginRecoverHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() }
loginRecoverButton.setOnClickListener { presenter.onRecoverClick() } loginRecoverButton.setOnClickListener { presenter.onRecoverClick() }
loginRecoverErrorRetry.setOnClickListener { presenter.onRecoverClick() } loginRecoverErrorRetry.setOnClickListener { presenter.onRecoverClick() }
loginRecoverErrorDetails.setOnClickListener { presenter.onDetailsClick() } loginRecoverErrorDetails.setOnClickListener { presenter.onDetailsClick() }
loginRecoverLogin.setOnClickListener { (activity as LoginActivity).switchView(0) } loginRecoverLogin.setOnClickListener { (activity as LoginActivity).switchView(0) }
loginRecoverSymbol.setAdapter(ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values)))
with(loginRecoverHost) { with(loginRecoverHost) {
setText(hostKeys.getOrNull(0).orEmpty()) setText(hostKeys.getOrNull(0).orEmpty())
setAdapter(LoginSymbolAdapter(context, R.layout.support_simple_spinner_dropdown_item, hostKeys)) setAdapter(LoginSymbolAdapter(context, R.layout.support_simple_spinner_dropdown_item, hostKeys))
@ -106,25 +105,10 @@ class LoginRecoverFragment : BaseFragment(), LoginRecoverView {
} }
} }
override fun setSymbolError(focus: Boolean) {
with(loginRecoverSymbolLayout) {
if (focus) requestFocus()
error = getString(R.string.login_field_required)
}
}
override fun clearUsernameError() { override fun clearUsernameError() {
loginRecoverNameLayout.error = null loginRecoverNameLayout.error = null
} }
override fun clearSymbolError() {
loginRecoverSymbolLayout.error = null
}
override fun showSymbol(show: Boolean) {
loginRecoverSymbolLayout.visibility = if (show) VISIBLE else GONE
}
override fun showProgress(show: Boolean) { override fun showProgress(show: Boolean) {
loginRecoverProgress.visibility = if (show) VISIBLE else GONE loginRecoverProgress.visibility = if (show) VISIBLE else GONE
} }

View File

@ -34,10 +34,6 @@ class LoginRecoverPresenter @Inject constructor(
view?.clearUsernameError() view?.clearUsernameError()
} }
fun onSymbolTextChanged() {
view?.clearSymbolError()
}
fun onHostSelected() { fun onHostSelected() {
view?.run { view?.run {
if ("fakelog" in recoverHostValue) setDefaultCredentials("jan@fakelog.cf") if ("fakelog" in recoverHostValue) setDefaultCredentials("jan@fakelog.cf")
@ -48,7 +44,6 @@ class LoginRecoverPresenter @Inject constructor(
fun updateFields() { fun updateFields() {
view?.run { view?.run {
showSymbol("adfs" in recoverHostValue)
setUsernameHint(if ("standard" in recoverHostValue) emailHintString else loginPeselEmailHintString) setUsernameHint(if ("standard" in recoverHostValue) emailHintString else loginPeselEmailHintString)
} }
} }
@ -56,9 +51,9 @@ class LoginRecoverPresenter @Inject constructor(
fun onRecoverClick() { fun onRecoverClick() {
val username = view?.recoverNameValue.orEmpty() val username = view?.recoverNameValue.orEmpty()
val host = view?.recoverHostValue.orEmpty() val host = view?.recoverHostValue.orEmpty()
val symbol = view?.recoverSymbolValue.orEmpty() val symbol = view?.formHostSymbol.orEmpty()
if (!validateInput(username, host, symbol)) return if (!validateInput(username, host)) return
disposable.add(recoverRepository.getReCaptchaSiteKey(host, symbol.ifBlank { "Default" }) disposable.add(recoverRepository.getReCaptchaSiteKey(host, symbol.ifBlank { "Default" })
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
@ -75,12 +70,12 @@ class LoginRecoverPresenter @Inject constructor(
.subscribe({ (resetUrl, siteKey) -> .subscribe({ (resetUrl, siteKey) ->
view?.loadReCaptcha(siteKey, resetUrl) view?.loadReCaptcha(siteKey, resetUrl)
}) { }) {
Timber.e("Obtain captcha site key result: An exception occurred") Timber.i("Obtain captcha site key result: An exception occurred")
errorHandler.dispatch(it) errorHandler.dispatch(it)
}) })
} }
private fun validateInput(username: String, host: String, symbol: String): Boolean { private fun validateInput(username: String, host: String): Boolean {
var isCorrect = true var isCorrect = true
if (username.isEmpty()) { if (username.isEmpty()) {
@ -93,18 +88,13 @@ class LoginRecoverPresenter @Inject constructor(
isCorrect = false isCorrect = false
} }
if ("adfs" in host && symbol.isBlank()) {
view?.setSymbolError(focus = isCorrect)
isCorrect = false
}
return isCorrect return isCorrect
} }
fun onReCaptchaVerified(reCaptchaResponse: String) { fun onReCaptchaVerified(reCaptchaResponse: String) {
val username = view?.recoverNameValue.orEmpty() val username = view?.recoverNameValue.orEmpty()
val host = view?.recoverHostValue.orEmpty() val host = view?.recoverHostValue.orEmpty()
val symbol = view?.recoverSymbolValue.ifNullOrBlank { "Default" } val symbol = view?.formHostSymbol.ifNullOrBlank { "Default" }
with(disposable) { with(disposable) {
clear() clear()
@ -130,7 +120,7 @@ class LoginRecoverPresenter @Inject constructor(
analytics.logEvent("account_recover", "register" to host, "symbol" to symbol, "success" to true) analytics.logEvent("account_recover", "register" to host, "symbol" to symbol, "success" to true)
}) { }) {
Timber.e("Send recover request result: An exception occurred") Timber.i("Send recover request result: An exception occurred")
errorHandler.dispatch(it) errorHandler.dispatch(it)
analytics.logEvent("account_recover", "register" to host, "symbol" to symbol, "success" to false) analytics.logEvent("account_recover", "register" to host, "symbol" to symbol, "success" to false)
}) })

View File

@ -6,9 +6,9 @@ interface LoginRecoverView : BaseView {
val recoverHostValue: String val recoverHostValue: String
val recoverNameValue: String val formHostSymbol: String
val recoverSymbolValue: String val recoverNameValue: String
val emailHintString: String val emailHintString: String
@ -22,18 +22,12 @@ interface LoginRecoverView : BaseView {
fun clearUsernameError() fun clearUsernameError()
fun clearSymbolError()
fun showSymbol(show: Boolean)
fun setErrorNameRequired() fun setErrorNameRequired()
fun setUsernameHint(hint: String) fun setUsernameHint(hint: String)
fun setUsernameError(message: String) fun setUsernameError(message: String)
fun setSymbolError(focus: Boolean)
fun showSoftKeyboard() fun showSoftKeyboard()
fun hideSoftKeyboard() fun hideSoftKeyboard()

View File

@ -132,7 +132,7 @@ abstract class MainModule {
abstract fun bindLogViewerFragment(): LogViewerFragment abstract fun bindLogViewerFragment(): LogViewerFragment
@PerFragment @PerFragment
@ContributesAndroidInjector() @ContributesAndroidInjector
abstract fun bindContributorFragment(): ContributorFragment abstract fun bindContributorFragment(): ContributorFragment
@PerFragment @PerFragment

View File

@ -63,7 +63,7 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
messageContainer = messagePreviewContainer messageContainer = messagePreviewContainer
presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as Message) presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message)
} }
override fun initView() { override fun initView() {
@ -150,8 +150,8 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putSerializable(MESSAGE_ID_KEY, presenter.message) outState.putSerializable(MESSAGE_ID_KEY, presenter.message)
super.onSaveInstanceState(outState)
} }
override fun onDestroyView() { override fun onDestroyView() {

View File

@ -24,11 +24,12 @@ class MessagePreviewPresenter @Inject constructor(
private var retryCallback: () -> Unit = {} private var retryCallback: () -> Unit = {}
fun onAttachView(view: MessagePreviewView, message: Message) { fun onAttachView(view: MessagePreviewView, message: Message?) {
super.onAttachView(view) super.onAttachView(view)
view.initView() view.initView()
errorHandler.showErrorMessage = ::showErrorViewOnError errorHandler.showErrorMessage = ::showErrorViewOnError
loadData(message) this.message = message
loadData(requireNotNull(message))
} }
private fun onMessageLoadRetry(message: Message) { private fun onMessageLoadRetry(message: Message) {
@ -47,7 +48,7 @@ class MessagePreviewPresenter @Inject constructor(
Timber.i("Loading message ${message.messageId} preview started") Timber.i("Loading message ${message.messageId} preview started")
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getStudentById(message.studentId)
.flatMap { messageRepository.getMessage(it, message, true) } .flatMap { messageRepository.getMessage(it, message, true) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
@ -84,7 +85,8 @@ class MessagePreviewPresenter @Inject constructor(
private fun deleteMessage() { private fun deleteMessage() {
message?.let { message -> message?.let { message ->
disposable.add(messageRepository.deleteMessage(message) disposable.add(studentRepository.getCurrentStudent()
.flatMap { messageRepository.deleteMessage(it, message) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doOnSubscribe { .doOnSubscribe {

View File

@ -147,7 +147,7 @@ class SendMessageActivity : BaseActivity<SendMessagePresenter>(), SendMessageVie
} }
override fun popView() { override fun popView() {
onBackPressed() finish()
} }
private fun setUpExtendedHitArea() { private fun setUpExtendedHitArea() {

View File

@ -135,12 +135,12 @@ class SendMessagePresenter @Inject constructor(
if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(selectedRecipientChips) if (selectedRecipientChips.isNotEmpty()) setSelectedRecipients(selectedRecipientChips)
showContent(true) showContent(true)
} else { } else {
Timber.e("Loading recipients result: Can't find the reporting unit") Timber.i("Loading recipients result: Can't find the reporting unit")
view?.showEmpty(true) view?.showEmpty(true)
} }
} }
}, { }, {
Timber.e("Loading recipients result: An exception occurred") Timber.i("Loading recipients result: An exception occurred")
view?.showContent(true) view?.showContent(true)
errorHandler.dispatch(it) errorHandler.dispatch(it)
})) }))
@ -148,7 +148,8 @@ class SendMessagePresenter @Inject constructor(
private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) { private fun sendMessage(subject: String, content: String, recipients: List<Recipient>) {
Timber.i("Sending message started") Timber.i("Sending message started")
disposable.add(messageRepository.sendMessage(subject, content, recipients) disposable.add(studentRepository.getCurrentStudent()
.flatMap { messageRepository.sendMessage(it, subject, content, recipients) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doOnSubscribe { .doOnSubscribe {

View File

@ -49,8 +49,11 @@ class MobileDevicePresenter @Inject constructor(
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading mobile devices data started") Timber.i("Loading mobile devices data started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
.flatMap { mobileDeviceRepository.getDevices(it, forceRefresh) } semesterRepository.getCurrentSemester(student).flatMap { semester ->
mobileDeviceRepository.getDevices(student, semester, forceRefresh)
}
}
.map { items -> items.map { MobileDeviceItem(it) } } .map { items -> items.map { MobileDeviceItem(it) } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
@ -107,10 +110,11 @@ class MobileDevicePresenter @Inject constructor(
fun onUnregisterConfirmed(device: MobileDevice) { fun onUnregisterConfirmed(device: MobileDevice) {
Timber.i("Unregister device started") Timber.i("Unregister device started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
.flatMap { semester -> semesterRepository.getCurrentSemester(student).flatMap { semester ->
mobileDeviceRepository.unregisterDevice(semester, device) mobileDeviceRepository.unregisterDevice(student, semester, device)
.flatMap { mobileDeviceRepository.getDevices(semester, it) } .flatMap { mobileDeviceRepository.getDevices(student, semester, it) }
}
} }
.map { items -> items.map { MobileDeviceItem(it) } } .map { items -> items.map { MobileDeviceItem(it) } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -29,8 +29,11 @@ class MobileDeviceTokenPresenter @Inject constructor(
private fun loadData() { private fun loadData() {
Timber.i("Mobile device registration data started") Timber.i("Mobile device registration data started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
.flatMap { mobileDeviceRepository.getToken(it) } semesterRepository.getCurrentSemester(student).flatMap { semester ->
mobileDeviceRepository.getToken(student, semester)
}
}
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doFinally { view?.hideLoading() } .doFinally { view?.hideLoading() }

View File

@ -64,8 +64,11 @@ class SchoolPresenter @Inject constructor(
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading school info started") Timber.i("Loading school info started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMapMaybe { student ->
.flatMapMaybe { schoolRepository.getSchoolInfo(it, forceRefresh) } semesterRepository.getCurrentSemester(student).flatMapMaybe {
schoolRepository.getSchoolInfo(student, it, forceRefresh)
}
}
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread) .observeOn(schedulers.mainThread)
.doFinally { .doFinally {

View File

@ -52,8 +52,11 @@ class TeacherPresenter @Inject constructor(
private fun loadData(forceRefresh: Boolean = false) { private fun loadData(forceRefresh: Boolean = false) {
Timber.i("Loading teachers data started") Timber.i("Loading teachers data started")
disposable.add(studentRepository.getCurrentStudent() disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
.flatMap { teacherRepository.getTeachers(it, forceRefresh) } semesterRepository.getCurrentSemester(student).flatMap { semester ->
teacherRepository.getTeachers(student, semester, forceRefresh)
}
}
.map { it.filter { teacher -> teacher.name.isNotBlank() } } .map { it.filter { teacher -> teacher.name.isNotBlank() } }
.map { items -> items.map { TeacherItem(it, view?.noSubjectString.orEmpty()) } } .map { items -> items.map { TeacherItem(it, view?.noSubjectString.orEmpty()) } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -82,6 +82,8 @@ class SettingsFragment : PreferenceFragmentCompat(),
} }
override fun setSyncInProgress(inProgress: Boolean) { override fun setSyncInProgress(inProgress: Boolean) {
if (activity == null || !isAdded) return
findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run { findPreference<Preference>(getString(R.string.pref_key_services_force_sync))?.run {
isEnabled = !inProgress isEnabled = !inProgress
summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else "" summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else ""

View File

@ -58,16 +58,29 @@ class SettingsPresenter @Inject constructor(
fun onForceSyncDialogSubmit() { fun onForceSyncDialogSubmit() {
view?.run { view?.run {
Timber.i("Setting sync now started") val successString = syncSuccessString
analytics.logEvent("sync_now_started") val failedString = syncFailedString
disposable.add(syncManager.startOneTimeSyncWorker() disposable.add(syncManager.startOneTimeSyncWorker()
.doOnSubscribe { setSyncInProgress(true) } .doOnSubscribe {
setSyncInProgress(true)
Timber.i("Setting sync now started")
analytics.logEvent("sync_now", "status" to "started")
}
.doFinally { setSyncInProgress(false) } .doFinally { setSyncInProgress(false) }
.subscribe({ workInfo -> .subscribe({ workInfo ->
if (workInfo.state == WorkInfo.State.SUCCEEDED) showMessage(syncSuccessString) when (workInfo.state) {
else if (workInfo.state == WorkInfo.State.FAILED) showError(syncFailedString, Throwable(workInfo.outputData.getString("error"))) WorkInfo.State.SUCCEEDED -> {
showMessage(successString)
analytics.logEvent("sync_now", "status" to "success")
}
WorkInfo.State.FAILED -> {
showError(failedString, Throwable(workInfo.outputData.getString("error")))
analytics.logEvent("sync_now", "status" to "failed")
}
else -> Timber.d("Sync now state: ${workInfo.state}")
}
}, { }, {
Timber.e("Sync now failed") Timber.e(it, "Sync now failed")
}) })
) )
} }

View File

@ -134,9 +134,12 @@ class TimetablePresenter @Inject constructor(
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
semesterRepository.getCurrentSemester(student).flatMap { semester ->
timetableRepository.getTimetable(student, semester, currentDate, currentDate, forceRefresh)
}
}
.delay(200, MILLISECONDS) .delay(200, MILLISECONDS)
.flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) }
.map { createTimetableItems(it) } .map { createTimetableItems(it) }
.map { items -> items.sortedWith(compareBy({ it.lesson.number }, { !it.lesson.isStudentPlan })) } .map { items -> items.sortedWith(compareBy({ it.lesson.number }, { !it.lesson.isStudentPlan })) }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -114,9 +114,12 @@ class CompletedLessonsPresenter @Inject constructor(
disposable.apply { disposable.apply {
clear() clear()
add(studentRepository.getCurrentStudent() add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) } .flatMap { student ->
semesterRepository.getCurrentSemester(student).flatMap { semester ->
completedLessonsRepository.getCompletedLessons(student, semester, currentDate, currentDate, forceRefresh)
}
}
.delay(200, TimeUnit.MILLISECONDS) .delay(200, TimeUnit.MILLISECONDS)
.flatMap { completedLessonsRepository.getCompletedLessons(it, currentDate, currentDate, forceRefresh) }
.map { items -> items.map { CompletedLessonItem(it) } } .map { items -> items.map { CompletedLessonItem(it) } }
.map { items -> items.sortedBy { it.completedLesson.number } } .map { items -> items.sortedBy { it.completedLesson.number } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -107,8 +107,11 @@ class TimetableWidgetFactory(
if (student != null) Maybe.just(student) if (student != null) Maybe.just(student)
else Maybe.empty() else Maybe.empty()
} }
.flatMap { semesterRepository.getCurrentSemester(it).toMaybe() } .flatMap { student ->
.flatMap { timetableRepository.getTimetable(it, date, date).toMaybe() } semesterRepository.getCurrentSemester(student).toMaybe().flatMap { semester ->
timetableRepository.getTimetable(student, semester, date, date).toMaybe()
}
}
.map { items -> items.sortedWith(compareBy({ it.number }, { !it.isStudentPlan })) } .map { items -> items.sortedWith(compareBy({ it.number }, { !it.isStudentPlan })) }
.map { lessons -> lessons.filter { if (prefRepository.showWholeClassPlan == "no") it.isStudentPlan else true } } .map { lessons -> lessons.filter { if (prefRepository.showWholeClassPlan == "no") it.isStudentPlan else true } }
.subscribeOn(schedulers.backgroundThread) .subscribeOn(schedulers.backgroundThread)

View File

@ -18,7 +18,7 @@ class DebugLogTree : Timber.DebugTree() {
} }
} }
private fun Bundle?.checkSavedState() = if (this == null) "(STATE IS NULL)" else "" private fun Bundle?.checkSavedState() = if (this == null) "(STATE IS NULL)" else "(STATE IS NOT NULL)"
class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks { class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks {

View File

@ -0,0 +1,23 @@
package io.github.wulkanowy.utils
import android.content.res.Resources
import io.github.wulkanowy.R
import io.github.wulkanowy.sdk.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.exception.NotLoggedInException
import io.github.wulkanowy.sdk.exception.PasswordChangeRequiredException
import io.github.wulkanowy.sdk.exception.ServiceUnavailableException
import java.io.InterruptedIOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
fun Resources.getString(error: Throwable) = when (error) {
is UnknownHostException -> getString(R.string.error_no_internet)
is SocketTimeoutException, is InterruptedIOException -> getString(R.string.error_timeout)
is NotLoggedInException -> getString(R.string.error_login_failed)
is PasswordChangeRequiredException -> getString(R.string.error_password_change_required)
is ServiceUnavailableException -> getString(R.string.error_service_unavailable)
is FeatureDisabledException -> getString(R.string.error_feature_disabled)
is FeatureNotAvailableException -> getString(R.string.error_feature_not_available)
else -> getString(R.string.error_unknown)
}

View File

@ -0,0 +1,29 @@
package io.github.wulkanowy.utils
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import timber.log.Timber
fun Sdk.init(student: Student): Sdk {
email = student.email
password = student.password
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
classId = student.classId
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
scrapperBaseUrl = student.scrapperBaseUrl
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
}
loginId = student.userLoginId
mode = Sdk.Mode.valueOf(student.loginMode)
mobileBaseUrl = student.mobileBaseUrl
certKey = student.certificateKey
privateKey = student.privateKey
Timber.d("Sdk in ${student.loginMode} mode reinitialized")
return this
}

View File

@ -1,11 +1,8 @@
Wersja 0.17.0 Wersja 0.17.2 i 0.17.3
- dodaliśmy wsparcie dla załączników w wiadomosciach i zadaniach domowych - naprawiliśmy wyświetlanie przycisku oznaczania zadania domowego jako wykonanego
- dodaliśmy oznaczanie zadań domowych jako wykonanych - naprawiliśmy rzadki błąd ze stabilnością przy wysyłaniu wiadomości
- dodaliśmy wyświetlanie punktów przy uwagach - naprawiliśmy błąd po logowaniu w domyślnym trybie, jeśli wcześniej użytkownik zalogowany był w trybie Mobilnego API
- dodaliśmy funkcję powiadomień o awariach dziennika - ulepszyliśmy wygląd okienka ze szczegółami błędu
- dodaliśmy funkcję wymuszenia pełnej synchronizacji
- zmieniliśmy sposób zwracania się do użytkownika na bezosobowy
- naprawiliśmy logowanie na androidach niższych niż 5.0
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -1,27 +1,49 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="300dp" android:minWidth="300dp"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="20dp"
android:paddingTop="20dp"
android:text="@string/all_details"
android:textSize="20sp" />
<TextView
android:id="@+id/errorDialogMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:textSize="21sp"
tools:text="@tools:sample/lorem" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical"> android:orientation="vertical">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:id="@+id/errorDialogNestedScroll"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:overScrollMode="ifContentScrolls"> android:overScrollMode="ifContentScrolls"
android:paddingHorizontal="24dp"
app:layout_constrainedHeight="true"
app:layout_constraintHeight_max="300dp"
app:layout_constraintHeight_min="200dp"
app:layout_constraintTop_toTopOf="parent">
<HorizontalScrollView <HorizontalScrollView
android:layout_width="350dp" android:id="@+id/errorDialogHorizontalScroll"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:paddingLeft="24dp" android:layout_height="wrap_content">
android:paddingTop="24dp"
android:paddingRight="24dp">
<TextView <TextView
android:id="@+id/errorDialogContent" android:id="@+id/errorDialogContent"
@ -33,16 +55,31 @@
tools:text="@tools:sample/lorem/random" /> tools:text="@tools:sample/lorem/random" />
</HorizontalScrollView> </HorizontalScrollView>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="24dp" android:background="@drawable/ic_all_divider"
android:gravity="end" android:gravity="end"
android:minHeight="52dp" android:minHeight="52dp"
android:orientation="horizontal"> android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/errorDialogReport"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="@string/about_feedback" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/errorDialogCancel" android:id="@+id/errorDialogCancel"
style="@style/Widget.MaterialComponents.Button.TextButton" style="@style/Widget.MaterialComponents.Button.TextButton"
@ -50,7 +87,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@android:string/cancel" /> android:text="@android:string/cancel" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
@ -60,7 +96,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@android:string/copy" /> android:text="@android:string/copy" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -1,143 +1,47 @@
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/parent"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout <androidx.recyclerview.widget.RecyclerView
android:layout_width="300dp" android:id="@+id/homeworkDialogRecycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:minWidth="300dp"
tools:itemCount="1"
tools:listitem="@layout/item_homework_dialog_details" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:background="@drawable/ic_all_divider"
android:padding="20dp"> android:paddingHorizontal="10dp"
android:paddingVertical="5dp">
<TextView <com.google.android.material.button.MaterialButton
android:id="@+id/homeworkDialogRead"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp" android:layout_alignParentStart="true"
android:layout_marginBottom="20dp" android:layout_alignParentBottom="true"
android:text="@string/all_details" android:text="@string/homework_mark_as_done"
android:textSize="20sp" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView <com.google.android.material.button.MaterialButton
android:id="@+id/homeworkDialogClose"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/all_subject" android:layout_alignParentEnd="true"
android:textSize="17sp" /> android:layout_alignParentBottom="true"
android:text="@string/all_close"
<TextView app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/homeworkDialogSubject" app:layout_constraintEnd_toEndOf="parent" />
android:layout_width="wrap_content" </androidx.constraintlayout.widget.ConstraintLayout>
android:layout_height="wrap_content" </LinearLayout>
android:layout_marginTop="3dp"
android:text="@string/all_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/all_teacher"
android:textSize="17sp" />
<TextView
android:id="@+id/homeworkDialogTeacher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/all_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/all_date"
android:textSize="17sp" />
<TextView
android:id="@+id/homeworkDialogDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/all_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/all_entry_date"
android:textSize="17sp" />
<TextView
android:id="@+id/homeworkDialogEntryDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/all_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/all_content"
android:textSize="17sp" />
<TextView
android:id="@+id/homeworkDialogContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:lineSpacingMultiplier="1.2"
android:text="@string/all_no_data"
android:textIsSelectable="true"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/homework_attachments"
android:textSize="17sp" />
<TextView
android:id="@+id/homeworkDialogAttachments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:lineSpacingMultiplier="1.2"
android:text="@string/all_no_data"
android:textIsSelectable="true"
android:textSize="14sp" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/homeworkDialogRead"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/homework_mark_as_done"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/homeworkDialogClose"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:text="@string/all_close"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -202,7 +202,7 @@
android:layout_marginRight="24dp" android:layout_marginRight="24dp"
android:hint="@string/login_host_hint" android:hint="@string/login_host_hint"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/loginFormSymbolLayout" app:layout_constraintBottom_toTopOf="@+id/loginFormAdvancedButton"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginFormRecoverLink"> app:layout_constraintTop_toBottomOf="@+id/loginFormRecoverLink">
@ -215,36 +215,6 @@
tools:ignore="Deprecated,LabelFor" /> tools:ignore="Deprecated,LabelFor" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginFormSymbolLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:hint="@string/login_symbol_hint"
app:errorEnabled="true"
app:layout_constraintBottom_toTopOf="@+id/loginFormSignIn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout">
<AutoCompleteTextView
android:id="@+id/loginFormSymbol"
style="@style/Widget.MaterialComponents.TextInputEditText.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeActionLabel="@string/login_sign_in"
android:imeOptions="actionDone"
android:importantForAutofill="no"
android:inputType="textAutoComplete|textNoSuggestions"
android:maxLines="1"
tools:ignore="LabelFor" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/loginFormAdvancedButton" android:id="@+id/loginFormAdvancedButton"
style="@style/Widget.MaterialComponents.Button.OutlinedButton" style="@style/Widget.MaterialComponents.Button.OutlinedButton"
@ -259,7 +229,7 @@
app:layout_constraintBottom_toBottomOf="@id/loginFormSignIn" app:layout_constraintBottom_toBottomOf="@id/loginFormSignIn"
app:layout_constraintEnd_toStartOf="@+id/loginFormSignIn" app:layout_constraintEnd_toStartOf="@+id/loginFormSignIn"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@id/loginFormSymbolLayout" app:layout_constraintStart_toStartOf="@id/loginFormHostLayout"
app:layout_constraintTop_toTopOf="@+id/loginFormSignIn" /> app:layout_constraintTop_toTopOf="@+id/loginFormSignIn" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
@ -274,7 +244,7 @@
android:text="@string/login_sign_in" android:text="@string/login_sign_in"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginFormSymbolLayout" /> app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout" />
<TextView <TextView
android:id="@+id/loginFormPrivacyLink" android:id="@+id/loginFormPrivacyLink"

View File

@ -88,6 +88,7 @@
android:autofillHints="emailAddress" android:autofillHints="emailAddress"
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:maxLines="1" android:maxLines="1"
android:imeOptions="actionDone"
tools:targetApi="o" /> tools:targetApi="o" />
<requestFocus /> <requestFocus />
@ -105,7 +106,7 @@
android:layout_marginRight="24dp" android:layout_marginRight="24dp"
android:hint="@string/login_host_hint" android:hint="@string/login_host_hint"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@+id/loginRecoverSymbolLayout" app:layout_constraintBottom_toTopOf="@+id/loginRecoverButton"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginRecoverNameLayout"> app:layout_constraintTop_toBottomOf="@+id/loginRecoverNameLayout">
@ -118,46 +119,17 @@
tools:ignore="Deprecated,LabelFor" /> tools:ignore="Deprecated,LabelFor" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/loginRecoverSymbolLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:hint="@string/login_symbol_hint"
app:errorEnabled="true"
app:layout_constraintBottom_toTopOf="@+id/loginRecoverButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginRecoverHostLayout">
<AutoCompleteTextView
android:id="@+id/loginRecoverSymbol"
style="@style/Widget.MaterialComponents.TextInputEditText.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeActionLabel="@string/login_sign_in"
android:imeOptions="actionDone"
android:inputType="textAutoComplete|textNoSuggestions"
android:maxLines="1"
tools:ignore="LabelFor" />
</com.google.android.material.textfield.TextInputLayout>
<Button <Button
android:id="@+id/loginRecoverButton" android:id="@+id/loginRecoverButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="24dp"
android:layout_marginEnd="24dp" android:layout_marginEnd="24dp"
android:layout_marginRight="24dp" android:layout_marginRight="24dp"
android:text="@string/login_recover" android:text="@string/login_recover"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/loginRecoverSymbolLayout" /> app:layout_constraintTop_toBottomOf="@+id/loginRecoverHostLayout" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@ -0,0 +1,21 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:paddingStart="20dp"
android:paddingTop="3dp"
android:paddingEnd="10dp"
android:paddingBottom="3dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/homeworkDialogAttachment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="10dp"
android:textSize="12sp"
app:drawableStartCompat="@drawable/ic_attachment"
app:drawableTint="?colorOnBackground"
tools:text="@tools:sample/lorem" />
</LinearLayout>

View File

@ -0,0 +1,14 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="20dp"
android:paddingEnd="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="3dp"
android:text="@string/homework_attachments"
android:textSize="17sp" />
</LinearLayout>

Some files were not shown because too many files have changed in this diff Show More