forked from github/wulkanowy-mirror
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
f2fa04105d | |||
7d97d71066 | |||
8daea5c900 | |||
297a2909ba | |||
935bec3f5b | |||
e71dd55066 | |||
4e3864f26f | |||
8601093725 | |||
b97b94ae29 | |||
c6c7357623 | |||
c2ab53cfeb | |||
87268b3ef6 | |||
b3cd7e8ac1 | |||
5a997dacb7 | |||
ed9458d9a5 | |||
3656d3161f | |||
d178c15d2f | |||
1f65b8465e | |||
6bb03b3be8 | |||
68b9847927 | |||
e1a83927c4 | |||
fc9981aa5d | |||
2d6610e05c | |||
316cd2f7f9 | |||
36785f019a | |||
4b78862486 | |||
20d0abba29 | |||
5add95ece1 | |||
575e244b3a | |||
8db73e9459 | |||
040857ba20 |
@ -14,6 +14,7 @@ cache:
|
||||
#branches:
|
||||
# only:
|
||||
# - master
|
||||
# - 0.7.x
|
||||
|
||||
android:
|
||||
licenses:
|
||||
|
@ -16,8 +16,8 @@ android {
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
versionCode 26
|
||||
versionName "0.7.0"
|
||||
versionCode 31
|
||||
versionName "0.7.5"
|
||||
multiDexEnabled true
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@ -25,6 +25,15 @@ android {
|
||||
fabric_api_key: System.getenv("FABRIC_API_KEY") ?: "null",
|
||||
crashlytics_enabled: project.hasProperty("enableCrashlytics")
|
||||
]
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
@ -77,7 +86,7 @@ play {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation('io.github.wulkanowy:api:0.7.0') { exclude module: "threetenbp" }
|
||||
implementation('io.github.wulkanowy:api:0.7.5') { exclude module: "threetenbp" }
|
||||
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||
@ -86,10 +95,14 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||
|
||||
implementation "android.arch.work:work-rxjava2:1.0.0"
|
||||
implementation "android.arch.work:work-runtime:1.0.0"
|
||||
implementation "android.arch.work:work-rxjava2:1.0.0"
|
||||
|
||||
implementation "androidx.room:room-runtime:2.1.0-alpha06"
|
||||
implementation "androidx.room:room-rxjava2:2.1.0-alpha06"
|
||||
kapt "androidx.room:room-compiler:2.1.0-alpha06"
|
||||
|
||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||
|
||||
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.3'
|
||||
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.3'
|
||||
@ -98,17 +111,13 @@ dependencies {
|
||||
kapt "com.google.dagger:dagger-compiler:2.21"
|
||||
kapt "com.google.dagger:dagger-android-processor:2.21"
|
||||
|
||||
implementation "androidx.room:room-runtime:2.1.0-alpha05"
|
||||
implementation "androidx.room:room-rxjava2:2.1.0-alpha05"
|
||||
kapt "androidx.room:room-compiler:2.1.0-alpha05"
|
||||
|
||||
implementation "eu.davidea:flexible-adapter:5.1.0"
|
||||
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
||||
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
||||
implementation 'com.ncapdevi:frag-nav:3.1.0'
|
||||
implementation 'com.ncapdevi:frag-nav:3.2.0'
|
||||
|
||||
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
|
||||
implementation 'com.github.PhilJay:MPAndroidChart:971640b29d'
|
||||
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
||||
|
||||
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2'
|
||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||
@ -128,15 +137,16 @@ dependencies {
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
|
||||
|
||||
testImplementation "junit:junit:4.12"
|
||||
testImplementation "io.mockk:mockk:1.9.1"
|
||||
testImplementation "org.mockito:mockito-inline:2.25.0"
|
||||
testImplementation "io.mockk:mockk:1.9.2"
|
||||
testImplementation "org.mockito:mockito-inline:2.25.1"
|
||||
testImplementation 'org.threeten:threetenbp:1.3.8'
|
||||
|
||||
androidTestImplementation "io.mockk:mockk-android:1.9.1"
|
||||
androidTestImplementation 'androidx.test:core:1.1.0'
|
||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||
androidTestImplementation 'org.mockito:mockito-android:2.25.0'
|
||||
androidTestImplementation "io.mockk:mockk-android:1.9.2"
|
||||
androidTestImplementation 'org.mockito:mockito-android:2.25.1'
|
||||
androidTestImplementation "androidx.room:room-testing:2.1.0-alpha06"
|
||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||
}
|
||||
|
||||
|
1325
app/schemas/io.github.wulkanowy.data.db.AppDatabase/11.json
Normal file
1325
app/schemas/io.github.wulkanowy.data.db.AppDatabase/11.json
Normal file
File diff suppressed because it is too large
Load Diff
1332
app/schemas/io.github.wulkanowy.data.db.AppDatabase/12.json
Normal file
1332
app/schemas/io.github.wulkanowy.data.db.AppDatabase/12.json
Normal file
File diff suppressed because it is too large
Load Diff
1356
app/schemas/io.github.wulkanowy.data.db.AppDatabase/13.json
Normal file
1356
app/schemas/io.github.wulkanowy.data.db.AppDatabase/13.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,31 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.room.testing.MigrationTestHelper
|
||||
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import org.junit.Rule
|
||||
|
||||
abstract class AbstractMigrationTest {
|
||||
|
||||
val dbName = "migration-test"
|
||||
|
||||
@get:Rule
|
||||
val helper: MigrationTestHelper = MigrationTestHelper(
|
||||
InstrumentationRegistry.getInstrumentation(),
|
||||
AppDatabase::class.java.canonicalName,
|
||||
FrameworkSQLiteOpenHelperFactory()
|
||||
)
|
||||
|
||||
fun getMigratedRoomDatabase(): AppDatabase {
|
||||
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
|
||||
AppDatabase::class.java, dbName)
|
||||
.addMigrations(Migration12(), Migration13())
|
||||
.build()
|
||||
// close the database and release any stream resources when the test finishes
|
||||
helper.closeWhenFinished(database)
|
||||
return database
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class Migration12Test : AbstractMigrationTest() {
|
||||
|
||||
@Test
|
||||
fun twoNotRelatedStudents() {
|
||||
helper.createDatabase(dbName, 11).apply {
|
||||
// user 1
|
||||
createStudent(this, 1, true)
|
||||
createSemester(this, 1, false, 5, 1)
|
||||
createSemester(this, 1, true, 5, 2)
|
||||
|
||||
// user 2
|
||||
createStudent(this, 2, true)
|
||||
createSemester(this, 2, false, 6, 1)
|
||||
createSemester(this, 2, true, 6, 2)
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
val students = db.studentDao.loadAll().blockingGet()
|
||||
|
||||
assertEquals(2, students.size)
|
||||
|
||||
students[0].run {
|
||||
assertEquals(1, studentId)
|
||||
assertEquals(5, classId)
|
||||
}
|
||||
|
||||
students[1].run {
|
||||
assertEquals(2, studentId)
|
||||
assertEquals(6, classId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removeStudentsWithoutClassId() {
|
||||
helper.createDatabase(dbName, 11).apply {
|
||||
// user 1
|
||||
createStudent(this, 1, true)
|
||||
createSemester(this, 1, false, 0, 2)
|
||||
createStudent(this, 2, true)
|
||||
createSemester(this, 2, true, 1, 2)
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
val students = db.studentDao.loadAll().blockingGet()
|
||||
|
||||
assertEquals(1, students.size)
|
||||
|
||||
students[0].run {
|
||||
assertEquals(2, studentId)
|
||||
assertEquals(1, classId)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ensureThereIsOnlyOneCurrentStudent() {
|
||||
helper.createDatabase(dbName, 11).apply {
|
||||
// user 1
|
||||
createStudent(this, 1, true)
|
||||
createSemester(this, 1, true, 5, 2)
|
||||
createStudent(this, 2, true)
|
||||
createSemester(this, 2, true, 6, 2)
|
||||
createStudent(this, 3, true)
|
||||
createSemester(this, 3, false, 7, 2)
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
val students = db.studentDao.loadAll().blockingGet()
|
||||
|
||||
assertEquals(3, students.size)
|
||||
|
||||
students[0].run {
|
||||
assertEquals(studentId, 1)
|
||||
assertEquals(false, isCurrent)
|
||||
}
|
||||
students[1].run {
|
||||
assertEquals(studentId, 2)
|
||||
assertEquals(false, isCurrent)
|
||||
}
|
||||
students[2].run {
|
||||
assertEquals(studentId, 3)
|
||||
assertEquals(true, isCurrent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean) {
|
||||
db.insert("Students", CONFLICT_FAIL, ContentValues().apply {
|
||||
put("endpoint", "https://fakelog.cf")
|
||||
put("loginType", "STANDARD")
|
||||
put("email", "jan@fakelog.cf")
|
||||
put("password", "******")
|
||||
put("symbol", "Default")
|
||||
put("student_id", studentId)
|
||||
put("student_name", "Jan Kowalski")
|
||||
put("school_id", "000123")
|
||||
put("school_name", "")
|
||||
put("is_current", isCurrent)
|
||||
put("registration_date", "0")
|
||||
})
|
||||
}
|
||||
|
||||
private fun createSemester(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean, classId: Int, diaryId: Int) {
|
||||
db.insert("Semesters", CONFLICT_FAIL, ContentValues().apply {
|
||||
put("student_id", studentId)
|
||||
put("diary_id", diaryId)
|
||||
put("diary_name", "IA")
|
||||
put("semester_id", diaryId * 5)
|
||||
put("semester_name", "1")
|
||||
put("is_current", isCurrent)
|
||||
put("class_id", classId)
|
||||
put("unit_id", "99")
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Test
|
||||
import org.threeten.bp.LocalDate.of
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class Migration13Test : AbstractMigrationTest() {
|
||||
|
||||
@Test
|
||||
fun studentsWithSchoolNameWithClassName() {
|
||||
helper.createDatabase(dbName, 12).apply {
|
||||
createStudent(this, 1, "Klasa A - Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", 1, 1)
|
||||
createStudent(this, 2, "Klasa B - Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", 2, 1)
|
||||
createStudent(this, 2, "Klasa C - Publiczna szkoła Wulkanowego-fejka nr 2 w fakelog.cf", 1, 2)
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
val students = db.studentDao.loadAll().blockingGet()
|
||||
|
||||
assertEquals(3, students.size)
|
||||
|
||||
students[0].run {
|
||||
assertEquals(1, studentId)
|
||||
assertEquals("A", className)
|
||||
assertEquals("Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", schoolName)
|
||||
}
|
||||
|
||||
students[1].run {
|
||||
assertEquals(2, studentId)
|
||||
assertEquals("B", className)
|
||||
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", schoolName)
|
||||
}
|
||||
|
||||
students[2].run {
|
||||
assertEquals(2, studentId)
|
||||
assertEquals("C", className)
|
||||
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 2 w fakelog.cf", schoolName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun studentsWithSchoolNameWithoutClassName() {
|
||||
helper.createDatabase(dbName, 12).apply {
|
||||
createStudent(this, 1, "Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", 1)
|
||||
createStudent(this, 2, "Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", 1)
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
val students = db.studentDao.loadAll().blockingGet()
|
||||
|
||||
assertEquals(2, students.size)
|
||||
|
||||
students[0].run {
|
||||
assertEquals(1, studentId)
|
||||
assertEquals("", className)
|
||||
assertEquals("Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", schoolName)
|
||||
}
|
||||
|
||||
students[1].run {
|
||||
assertEquals(2, studentId)
|
||||
assertEquals("", className)
|
||||
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", schoolName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun markAtLeastAndOnlyOneSemesterAtCurrent() {
|
||||
helper.createDatabase(dbName, 12).apply {
|
||||
createStudent(this, 1, "", 5)
|
||||
createSemester(this, 1, 5, 1, 1, false)
|
||||
createSemester(this, 1, 5, 2, 1, false)
|
||||
createSemester(this, 1, 5, 3, 2, false)
|
||||
createSemester(this, 1, 5, 4, 2, false)
|
||||
|
||||
createStudent(this, 2, "", 5)
|
||||
createSemester(this, 2, 5, 5, 5, true)
|
||||
createSemester(this, 2, 5, 6, 5, true)
|
||||
createSemester(this, 2, 5, 7, 55, true)
|
||||
createSemester(this, 2, 5, 8, 55, true)
|
||||
|
||||
createStudent(this, 3, "", 5)
|
||||
createSemester(this, 3, 5, 11, 99, false)
|
||||
createSemester(this, 3, 5, 12, 99, false)
|
||||
createSemester(this, 3, 5, 13, 100, false)
|
||||
createSemester(this, 3, 5, 14, 100, true)
|
||||
close()
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
|
||||
|
||||
val db = getMigratedRoomDatabase()
|
||||
|
||||
val semesters1 = db.semesterDao.loadAll(1, 5).blockingGet()
|
||||
assertTrue { semesters1.single { it.isCurrent }.isCurrent }
|
||||
semesters1[0].run {
|
||||
assertFalse(isCurrent)
|
||||
assertEquals(1, semesterId)
|
||||
assertEquals(1, diaryId)
|
||||
}
|
||||
semesters1[2].run {
|
||||
assertFalse(isCurrent)
|
||||
assertEquals(3, semesterId)
|
||||
assertEquals(2, diaryId)
|
||||
}
|
||||
semesters1[3].run {
|
||||
assertTrue(isCurrent)
|
||||
assertEquals(4, semesterId)
|
||||
assertEquals(2, diaryId)
|
||||
}
|
||||
|
||||
db.semesterDao.loadAll(2, 5).blockingGet().let {
|
||||
assertTrue { it.single { it.isCurrent }.isCurrent }
|
||||
assertEquals(1970, it[0].schoolYear)
|
||||
assertEquals(of(1970, 1, 1), it[0].end)
|
||||
assertEquals(of(1970, 1, 1), it[0].start)
|
||||
assertFalse(it[0].isCurrent)
|
||||
assertFalse(it[1].isCurrent)
|
||||
assertFalse(it[2].isCurrent)
|
||||
assertTrue(it[3].isCurrent)
|
||||
}
|
||||
|
||||
db.semesterDao.loadAll(2, 5).blockingGet().let {
|
||||
assertTrue { it.single { it.isCurrent }.isCurrent }
|
||||
assertFalse(it[0].isCurrent)
|
||||
assertFalse(it[1].isCurrent)
|
||||
assertFalse(it[2].isCurrent)
|
||||
assertTrue(it[3].isCurrent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, schoolName: String = "", classId: Int = -1, schoolId: Int = 123) {
|
||||
db.insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
|
||||
put("endpoint", "https://fakelog.cf")
|
||||
put("loginType", "STANDARD")
|
||||
put("email", "jan@fakelog.cf")
|
||||
put("password", "******")
|
||||
put("symbol", "Default")
|
||||
put("student_id", studentId)
|
||||
put("class_id", classId)
|
||||
put("student_name", "Jan Kowalski")
|
||||
put("school_id", schoolId)
|
||||
put("school_name", schoolName)
|
||||
put("is_current", false)
|
||||
put("registration_date", "0")
|
||||
})
|
||||
}
|
||||
|
||||
private fun createSemester(db: SupportSQLiteDatabase, studentId: Int, classId: Int, semesterId: Int, diaryId: Int, isCurrent: Boolean = false) {
|
||||
db.insert("Semesters", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
|
||||
put("student_id", studentId)
|
||||
put("diary_id", diaryId)
|
||||
put("diary_name", "IA")
|
||||
put("semester_id", semesterId)
|
||||
put("semester_name", "1")
|
||||
put("is_current", isCurrent)
|
||||
put("class_id", classId)
|
||||
put("unit_id", "99")
|
||||
})
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@ -40,7 +41,7 @@ class AttendanceLocalTest {
|
||||
))
|
||||
|
||||
val attendance = attendanceLocal
|
||||
.getAttendance(Semester(1, 2, "", 1, 3, true, 1, 1),
|
||||
.getAttendance(Semester(1, 2, "", 1, 3, 2019, true, now(), now(), 1, 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
)
|
||||
|
@ -41,7 +41,7 @@ class CompletedLessonsLocalTest {
|
||||
))
|
||||
|
||||
val completed = completedLessonsLocal
|
||||
.getCompletedLessons(Semester(1, 2, "", 1, 3, true, 1, 1),
|
||||
.getCompletedLessons(Semester(1, 2, "", 1, 3, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
)
|
||||
|
@ -40,7 +40,7 @@ class ExamLocalTest {
|
||||
))
|
||||
|
||||
val exams = examLocal
|
||||
.getExams(Semester(1, 2, "", 1, 3, true, 1, 1),
|
||||
.getExams(Semester(1, 2, "", 1, 3, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
)
|
||||
|
@ -10,6 +10,7 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.threeten.bp.LocalDate
|
||||
import org.threeten.bp.LocalDate.now
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@ -34,13 +35,15 @@ class GradeLocalTest {
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
gradeLocal.saveGrades(listOf(
|
||||
createGradeLocal(5, 3, LocalDate.of(2018, 9, 10), "", 1),
|
||||
createGradeLocal(4, 4, LocalDate.of(2019, 2, 27), "", 2),
|
||||
createGradeLocal(3, 5, LocalDate.of(2019, 2, 28), "", 2)
|
||||
createGradeLocal(5, 3.0, LocalDate.of(2018, 9, 10), "", 1),
|
||||
createGradeLocal(4, 4.0, LocalDate.of(2019, 2, 27), "", 2),
|
||||
createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 2)
|
||||
))
|
||||
|
||||
val semester = Semester(1, 2, "", 2019, 2, 1, true, now(), now(), 1, 1)
|
||||
|
||||
val grades = gradeLocal
|
||||
.getGrades(Semester(1, 2, "", 2, 3, true, 1, 1))
|
||||
.getGrades(semester)
|
||||
.blockingGet()
|
||||
|
||||
assertEquals(2, grades.size)
|
||||
|
@ -71,10 +71,10 @@ class GradeRepositoryTest {
|
||||
@Test
|
||||
fun markOlderThanRegisterDateAsRead() {
|
||||
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||
createGradeApi(5, 4, of(2019, 2, 25), "Ocena pojawiła się"),
|
||||
createGradeApi(5, 4, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
|
||||
createGradeApi(5, 4, of(2019, 2, 27), "Ocena z dnia logowania"),
|
||||
createGradeApi(5, 4, of(2019, 2, 28), "Ocena jeszcze nowsza")
|
||||
createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
|
||||
createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
|
||||
createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
|
||||
createGradeApi(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
|
||||
))
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
@ -89,16 +89,16 @@ class GradeRepositoryTest {
|
||||
@Test
|
||||
fun mitigateOldGradesNotifications() {
|
||||
gradeLocal.saveGrades(listOf(
|
||||
createGradeLocal(5, 3, of(2019, 2, 25), "Jedna ocena"),
|
||||
createGradeLocal(4, 4, of(2019, 2, 26), "Druga"),
|
||||
createGradeLocal(3, 5, of(2019, 2, 27), "Trzecia")
|
||||
createGradeLocal(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
|
||||
createGradeLocal(4, 4.0, of(2019, 2, 26), "Druga"),
|
||||
createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
|
||||
))
|
||||
|
||||
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||
createGradeApi(5, 2, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
|
||||
createGradeApi(4, 3, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
|
||||
createGradeApi(3, 4, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
|
||||
createGradeApi(2, 5, of(2019, 2, 28), "Ta jest już w ogóle nowa")
|
||||
createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
|
||||
createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
|
||||
createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
|
||||
createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
|
||||
))
|
||||
|
||||
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||
|
@ -5,7 +5,7 @@ import org.threeten.bp.LocalDate
|
||||
import io.github.wulkanowy.api.grades.Grade as GradeRemote
|
||||
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal
|
||||
|
||||
fun createGradeLocal(value: Int, weight: Int, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
|
||||
fun createGradeLocal(value: Int, weight: Double, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
|
||||
return GradeLocal(
|
||||
semesterId = semesterId,
|
||||
studentId = 1,
|
||||
@ -24,7 +24,7 @@ fun createGradeLocal(value: Int, weight: Int, date: LocalDate, desc: String, sem
|
||||
)
|
||||
}
|
||||
|
||||
fun createGradeApi(value: Int, weight: Int, date: LocalDate, desc: String): GradeRemote {
|
||||
fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String): GradeRemote {
|
||||
return GradeRemote().apply {
|
||||
this.value = value
|
||||
this.weightValue = weight
|
||||
|
@ -10,6 +10,7 @@ import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.threeten.bp.LocalDate
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@ -39,7 +40,7 @@ class GradeStatisticsLocalTest {
|
||||
))
|
||||
|
||||
val stats = gradeStatisticsLocal.getGradesStatistics(
|
||||
Semester(2, 2, "", 1, 2, true, 1, 1), false,
|
||||
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1), false,
|
||||
"Matematyka"
|
||||
).blockingGet()
|
||||
assertEquals(1, stats.size)
|
||||
@ -55,7 +56,7 @@ class GradeStatisticsLocalTest {
|
||||
))
|
||||
|
||||
val stats = gradeStatisticsLocal.getGradesStatistics(
|
||||
Semester(2, 2, "", 1, 2, true, 1, 1), false,
|
||||
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1), false,
|
||||
"Wszystkie"
|
||||
).blockingGet()
|
||||
assertEquals(1, stats.size)
|
||||
|
@ -36,7 +36,7 @@ class LuckyNumberLocalTest {
|
||||
fun saveAndReadTest() {
|
||||
luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
|
||||
|
||||
val luckyNumber = luckyNumberLocal.getLuckyNumber(Semester(1, 1, "", 1, 3, true, 1, 1),
|
||||
val luckyNumber = luckyNumberLocal.getLuckyNumber(Semester(1, 1, "", 1, 3, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
LocalDate.of(2019, 1, 20)
|
||||
).blockingGet()
|
||||
|
||||
|
@ -42,7 +42,7 @@ class RecipientLocalTest {
|
||||
))
|
||||
|
||||
val recipients = recipientLocal.getRecipients(
|
||||
Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", true, LocalDateTime.now()),
|
||||
Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", "", 1, true, LocalDateTime.now()),
|
||||
2,
|
||||
ReportingUnit(1, 4, "", 0, "", emptyList())
|
||||
).blockingGet()
|
||||
|
@ -39,7 +39,7 @@ class StudentLocalTest {
|
||||
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, symbol = "", registrationDate = now()))
|
||||
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = ""))
|
||||
.blockingGet()
|
||||
|
||||
val student = studentLocal.getCurrentStudent(true).blockingGet()
|
||||
|
@ -41,7 +41,7 @@ class TimetableLocalTest {
|
||||
))
|
||||
|
||||
val exams = timetableDb.getTimetable(
|
||||
Semester(1, 2, "", 1, 1, true, 1, 1),
|
||||
Semester(1, 2, "", 1, 1, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
|
||||
LocalDate.of(2018, 9, 10),
|
||||
LocalDate.of(2018, 9, 14)
|
||||
).blockingGet()
|
||||
|
@ -39,18 +39,12 @@
|
||||
android:name=".ui.modules.main.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/main_title"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||
<activity
|
||||
android:name=".ui.modules.message.send.SendMessageActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/send_message_title"
|
||||
android:parentActivityName=".ui.modules.main.MainActivity"
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ui.modules.main.MainActivity" />
|
||||
</activity>
|
||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||
|
||||
<service
|
||||
android:name=".services.widgets.TimetableWidgetService"
|
||||
@ -58,6 +52,7 @@
|
||||
|
||||
<receiver
|
||||
android:name=".ui.widgets.timetable.TimetableWidgetProvider"
|
||||
android:exported="true"
|
||||
android:label="@string/timetable_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
|
@ -19,7 +19,11 @@ import io.github.wulkanowy.di.DaggerAppComponent
|
||||
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
||||
import io.github.wulkanowy.utils.CrashlyticsTree
|
||||
import io.github.wulkanowy.utils.DebugLogTree
|
||||
import io.reactivex.exceptions.UndeliverableException
|
||||
import io.reactivex.plugins.RxJavaPlugins
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
import javax.inject.Inject
|
||||
|
||||
class WulkanowyApp : DaggerApplication() {
|
||||
@ -42,6 +46,7 @@ class WulkanowyApp : DaggerApplication() {
|
||||
if (DEBUG) enableDebugLog()
|
||||
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
|
||||
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
||||
RxJavaPlugins.setErrorHandler(::onError)
|
||||
}
|
||||
|
||||
private fun enableDebugLog() {
|
||||
@ -56,6 +61,12 @@ class WulkanowyApp : DaggerApplication() {
|
||||
Timber.plant(CrashlyticsTree())
|
||||
}
|
||||
|
||||
private fun onError(t: Throwable) {
|
||||
if (t is UndeliverableException && t.cause is IOException || t.cause is InterruptedException) {
|
||||
Timber.e(t.cause, "An undeliverable error occurred")
|
||||
} else throw t
|
||||
}
|
||||
|
||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
|
||||
return DaggerAppComponent.builder().create(this)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ class ApiHelper @Inject constructor(private val api: Api) {
|
||||
symbol = student.symbol
|
||||
schoolSymbol = student.schoolSymbol
|
||||
studentId = student.studentId
|
||||
classId = student.classId
|
||||
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
|
||||
ssl = student.endpoint.startsWith("https")
|
||||
loginType = Api.LoginType.valueOf(student.loginType)
|
||||
@ -28,6 +29,7 @@ class ApiHelper @Inject constructor(private val api: Api) {
|
||||
this.symbol = symbol
|
||||
host = URL(endpoint).run { host + ":$port".removeSuffix(":-1") }
|
||||
ssl = endpoint.startsWith("https")
|
||||
useNewStudent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.Subject
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.github.wulkanowy.data.db.migrations.Migration10
|
||||
import io.github.wulkanowy.data.db.migrations.Migration11
|
||||
import io.github.wulkanowy.data.db.migrations.Migration12
|
||||
import io.github.wulkanowy.data.db.migrations.Migration13
|
||||
import io.github.wulkanowy.data.db.migrations.Migration2
|
||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||
@ -73,13 +76,13 @@ import javax.inject.Singleton
|
||||
Recipient::class
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = false
|
||||
exportSchema = true
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 10
|
||||
const val VERSION_SCHEMA = 13
|
||||
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||
@ -95,7 +98,10 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
Migration7(),
|
||||
Migration8(),
|
||||
Migration9(),
|
||||
Migration10()
|
||||
Migration10(),
|
||||
Migration11(),
|
||||
Migration12(),
|
||||
Migration13()
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package io.github.wulkanowy.data.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.IGNORE
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Maybe
|
||||
@ -12,15 +12,12 @@ import javax.inject.Singleton
|
||||
@Dao
|
||||
interface SemesterDao {
|
||||
|
||||
@Insert(onConflict = IGNORE)
|
||||
@Insert
|
||||
fun insertAll(semester: List<Semester>)
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||
fun loadAll(studentId: Int): Maybe<List<Semester>>
|
||||
@Delete
|
||||
fun deleteAll(semester: List<Semester>)
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId AND diary_id = :diaryId")
|
||||
fun updateCurrent(semesterId: Int, diaryId: Int)
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 0 WHERE student_id = :studentId")
|
||||
fun resetCurrent(studentId: Int)
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
|
||||
fun loadAll(studentId: Int, classId: Int): Maybe<List<Semester>>
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ interface StudentDao {
|
||||
@Query("SELECT * FROM Students")
|
||||
fun loadAll(): Maybe<List<Student>>
|
||||
|
||||
@Query("UPDATE Students SET is_current = 1 WHERE student_id = :studentId")
|
||||
fun updateCurrent(studentId: Int)
|
||||
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||
fun updateCurrent(id: Long)
|
||||
|
||||
@Query("UPDATE Students SET is_current = 0")
|
||||
fun resetCurrent()
|
||||
|
@ -34,7 +34,7 @@ data class Grade(
|
||||
|
||||
val weight: String,
|
||||
|
||||
val weightValue: Int,
|
||||
val weightValue: Double,
|
||||
|
||||
val date: LocalDate,
|
||||
|
||||
|
@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import org.threeten.bp.LocalDate
|
||||
|
||||
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
|
||||
data class Semester(
|
||||
@ -17,6 +18,9 @@ data class Semester(
|
||||
@ColumnInfo(name = "diary_name")
|
||||
val diaryName: String,
|
||||
|
||||
@ColumnInfo(name = "school_year")
|
||||
val schoolYear: Int,
|
||||
|
||||
@ColumnInfo(name = "semester_id")
|
||||
val semesterId: Int,
|
||||
|
||||
@ -26,6 +30,10 @@ data class Semester(
|
||||
@ColumnInfo(name = "is_current")
|
||||
val isCurrent: Boolean,
|
||||
|
||||
val start: LocalDate,
|
||||
|
||||
val end: LocalDate,
|
||||
|
||||
@ColumnInfo(name = "class_id")
|
||||
val classId: Int,
|
||||
|
||||
|
@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
||||
import org.threeten.bp.LocalDateTime
|
||||
import java.io.Serializable
|
||||
|
||||
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id"], unique = true)])
|
||||
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
|
||||
data class Student(
|
||||
|
||||
val endpoint: String,
|
||||
@ -32,6 +32,12 @@ data class Student(
|
||||
@ColumnInfo(name = "school_name")
|
||||
val schoolName: String,
|
||||
|
||||
@ColumnInfo(name = "class_name")
|
||||
val className: String,
|
||||
|
||||
@ColumnInfo(name = "class_id")
|
||||
val classId: Int,
|
||||
|
||||
@ColumnInfo(name = "is_current")
|
||||
val isCurrent: Boolean,
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration11 : Migration(10, 11) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("""
|
||||
CREATE TABLE IF NOT EXISTS Grades_temp (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
is_read INTEGER NOT NULL,
|
||||
is_notified INTEGER NOT NULL,
|
||||
semester_id INTEGER NOT NULL,
|
||||
student_id INTEGER NOT NULL,
|
||||
subject TEXT NOT NULL,
|
||||
entry TEXT NOT NULL,
|
||||
value INTEGER NOT NULL,
|
||||
modifier REAL NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
color TEXT NOT NULL,
|
||||
grade_symbol TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
weight TEXT NOT NULL,
|
||||
weightValue REAL NOT NULL,
|
||||
date INTEGER NOT NULL,
|
||||
teacher TEXT NOT NULL
|
||||
)
|
||||
""")
|
||||
database.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
|
||||
database.execSQL("DROP TABLE Grades")
|
||||
database.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration12 : Migration(11, 12) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
createTempStudentsTable(database)
|
||||
replaceStudentTable(database)
|
||||
updateStudentsWithClassId(database, getStudentsIds(database))
|
||||
removeStudentsWithNoClassId(database)
|
||||
ensureThereIsOnlyOneCurrentStudent(database)
|
||||
}
|
||||
|
||||
private fun createTempStudentsTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("""
|
||||
CREATE TABLE IF NOT EXISTS Students_tmp (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
endpoint TEXT NOT NULL,
|
||||
loginType TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
symbol TEXT NOT NULL,
|
||||
student_id INTEGER NOT NULL,
|
||||
student_name TEXT NOT NULL,
|
||||
school_id TEXT NOT NULL,
|
||||
school_name TEXT NOT NULL,
|
||||
is_current INTEGER NOT NULL,
|
||||
registration_date INTEGER NOT NULL,
|
||||
class_id INTEGER NOT NULL
|
||||
)
|
||||
""")
|
||||
database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students_tmp (email, symbol, student_id, school_id, class_id)")
|
||||
}
|
||||
|
||||
private fun replaceStudentTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE Students ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
|
||||
database.execSQL("INSERT INTO Students_tmp SELECT * FROM Students")
|
||||
database.execSQL("DROP TABLE Students")
|
||||
database.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
|
||||
}
|
||||
|
||||
private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> {
|
||||
val students = mutableListOf<Int>()
|
||||
val studentsCursor = database.query("SELECT student_id FROM Students")
|
||||
if (studentsCursor.moveToFirst()) {
|
||||
do {
|
||||
students.add(studentsCursor.getInt(0))
|
||||
} while (studentsCursor.moveToNext())
|
||||
}
|
||||
return students
|
||||
}
|
||||
|
||||
private fun updateStudentsWithClassId(database: SupportSQLiteDatabase, students: List<Int>) {
|
||||
students.forEach {
|
||||
database.execSQL("UPDATE Students SET class_id = IFNULL((SELECT class_id FROM Semesters WHERE student_id = $it), 0) WHERE student_id = $it")
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeStudentsWithNoClassId(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DELETE FROM Students WHERE class_id = 0")
|
||||
}
|
||||
|
||||
private fun ensureThereIsOnlyOneCurrentStudent(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("UPDATE Students SET is_current = 0")
|
||||
database.execSQL("UPDATE Students SET is_current = 1 WHERE id = (SELECT MAX(id) FROM Students)")
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package io.github.wulkanowy.data.db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
class Migration13 : Migration(12, 13) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
addClassNameToStudents(database, getStudentsIds(database))
|
||||
updateSemestersTable(database)
|
||||
markAtLeastAndOnlyOneSemesterAtCurrent(database, getStudentsAndClassIds(database))
|
||||
clearMessagesTable(database)
|
||||
}
|
||||
|
||||
private fun addClassNameToStudents(database: SupportSQLiteDatabase, students: List<Pair<Int, String>>) {
|
||||
database.execSQL("ALTER TABLE Students ADD COLUMN class_name TEXT DEFAULT \"\" NOT NULL")
|
||||
|
||||
students.forEach { (id, name) ->
|
||||
val schoolName = name.substringAfter(" - ")
|
||||
val className = name.substringBefore(" - ", "").replace("Klasa ", "")
|
||||
database.execSQL("UPDATE Students SET class_name = '$className' WHERE id = '$id'")
|
||||
database.execSQL("UPDATE Students SET school_name = '$schoolName' WHERE id = '$id'")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getStudentsIds(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
|
||||
val students = mutableListOf<Pair<Int, String>>()
|
||||
val studentsCursor = database.query("SELECT id, school_name FROM Students")
|
||||
if (studentsCursor.moveToFirst()) {
|
||||
do {
|
||||
students.add(studentsCursor.getInt(0) to studentsCursor.getString(1))
|
||||
} while (studentsCursor.moveToNext())
|
||||
}
|
||||
return students
|
||||
}
|
||||
|
||||
private fun updateSemestersTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE Semesters ADD COLUMN school_year INTEGER DEFAULT 1970 NOT NULL")
|
||||
database.execSQL("ALTER TABLE Semesters ADD COLUMN start INTEGER DEFAULT 0 NOT NULL")
|
||||
database.execSQL("ALTER TABLE Semesters ADD COLUMN `end` INTEGER DEFAULT 0 NOT NULL")
|
||||
}
|
||||
|
||||
private fun getStudentsAndClassIds(database: SupportSQLiteDatabase): List<Pair<Int, Int>> {
|
||||
val students = mutableListOf<Pair<Int, Int>>()
|
||||
val studentsCursor = database.query("SELECT student_id, class_id FROM Students")
|
||||
if (studentsCursor.moveToFirst()) {
|
||||
do {
|
||||
students.add(studentsCursor.getInt(0) to studentsCursor.getInt(1))
|
||||
} while (studentsCursor.moveToNext())
|
||||
}
|
||||
return students
|
||||
}
|
||||
|
||||
private fun markAtLeastAndOnlyOneSemesterAtCurrent(database: SupportSQLiteDatabase, students: List<Pair<Int, Int>>) {
|
||||
students.forEach { (studentId, classId) ->
|
||||
database.execSQL("UPDATE Semesters SET is_current = 0 WHERE student_id = '$studentId' AND class_id = '$classId'")
|
||||
database.execSQL("UPDATE Semesters SET is_current = 1 WHERE id = (SELECT id FROM Semesters WHERE student_id = '$studentId' AND class_id = '$classId' ORDER BY semester_id DESC)")
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearMessagesTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DELETE FROM Messages")
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package io.github.wulkanowy.data.exceptions
|
||||
|
||||
class NoCurrentStudentException : Exception("There no set current student in database")
|
@ -24,13 +24,13 @@ class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
|
||||
}
|
||||
|
||||
fun getMessage(student: Student, id: Int): Maybe<Message> {
|
||||
return messagesDb.load(student.studentId, id)
|
||||
return messagesDb.load(student.id.toInt(), id)
|
||||
}
|
||||
|
||||
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
|
||||
return when (folder) {
|
||||
TRASHED -> messagesDb.loadDeleted(student.studentId)
|
||||
else -> messagesDb.loadAll(student.studentId, folder.id)
|
||||
TRASHED -> messagesDb.loadDeleted(student.id.toInt())
|
||||
else -> messagesDb.loadAll(student.id.toInt(), folder.id)
|
||||
}.filter { it.isNotEmpty() }
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.api.messages.Folder
|
||||
import io.github.wulkanowy.api.messages.SentMessage
|
||||
import io.github.wulkanowy.data.db.entities.Message
|
||||
import io.github.wulkanowy.data.db.entities.Recipient
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.utils.toLocalDateTime
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDateTime.now
|
||||
@ -16,11 +17,11 @@ import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
|
||||
@Singleton
|
||||
class MessageRemote @Inject constructor(private val api: Api) {
|
||||
|
||||
fun getMessages(studentId: Int, folder: MessageFolder): Single<List<Message>> {
|
||||
fun getMessages(student: Student, folder: MessageFolder): Single<List<Message>> {
|
||||
return api.getMessages(Folder.valueOf(folder.name)).map { messages ->
|
||||
messages.map {
|
||||
Message(
|
||||
studentId = studentId,
|
||||
studentId = student.id.toInt(),
|
||||
realId = it.id ?: 0,
|
||||
messageId = it.messageId ?: 0,
|
||||
sender = it.sender.orEmpty(),
|
||||
|
@ -28,7 +28,7 @@ class MessageRepository @Inject constructor(
|
||||
local.getMessages(student, folder).filter { !forceRefresh }
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getMessages(student.studentId, folder)
|
||||
if (it) remote.getMessages(student, folder)
|
||||
else Single.error(UnknownHostException())
|
||||
}.flatMap { new ->
|
||||
local.getMessages(student, folder).toSingle(emptyList())
|
||||
|
@ -11,17 +11,14 @@ import javax.inject.Singleton
|
||||
class SemesterLocal @Inject constructor(private val semesterDb: SemesterDao) {
|
||||
|
||||
fun saveSemesters(semesters: List<Semester>) {
|
||||
return semesterDb.insertAll(semesters)
|
||||
semesterDb.insertAll(semesters)
|
||||
}
|
||||
|
||||
fun deleteSemesters(semesters: List<Semester>) {
|
||||
semesterDb.deleteAll(semesters)
|
||||
}
|
||||
|
||||
fun getSemesters(student: Student): Maybe<List<Semester>> {
|
||||
return semesterDb.loadAll(student.studentId).filter { !it.isEmpty() }
|
||||
}
|
||||
|
||||
fun setCurrentSemester(semester: Semester) {
|
||||
semesterDb.run {
|
||||
resetCurrent(semester.studentId)
|
||||
updateCurrent(semester.semesterId, semester.diaryId)
|
||||
}
|
||||
return semesterDb.loadAll(student.studentId, student.classId).filter { !it.isEmpty() }
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,12 @@ class SemesterRemote @Inject constructor(private val api: Api) {
|
||||
studentId = student.studentId,
|
||||
diaryId = semester.diaryId,
|
||||
diaryName = semester.diaryName,
|
||||
schoolYear = semester.schoolYear,
|
||||
semesterId = semester.semesterId,
|
||||
semesterName = semester.semesterNumber,
|
||||
isCurrent = semester.current,
|
||||
start = semester.start,
|
||||
end = semester.end,
|
||||
classId = semester.classId,
|
||||
unitId = semester.unitId
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import timber.log.Timber
|
||||
import java.net.UnknownHostException
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@ -25,10 +26,17 @@ class SemesterRepository @Inject constructor(
|
||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||
.flatMap {
|
||||
if (it) remote.getSemesters(student) else Single.error(UnknownHostException())
|
||||
}.map { newSemesters ->
|
||||
local.apply {
|
||||
saveSemesters(newSemesters)
|
||||
setCurrentSemester(newSemesters.single { it.isCurrent })
|
||||
}.flatMap { new ->
|
||||
val currentSemesters = new.filter { it.isCurrent }
|
||||
if (currentSemesters.size == 1) {
|
||||
local.getSemesters(student).toSingle(emptyList())
|
||||
.doOnSuccess { old ->
|
||||
local.deleteSemesters(old - new)
|
||||
local.saveSemesters(new - old)
|
||||
}
|
||||
} else {
|
||||
Timber.i("Current semesters list:\n${currentSemesters.joinToString(separator = "\n")}")
|
||||
throw IllegalArgumentException("Current semester can be only one.")
|
||||
}
|
||||
}.flatMap { local.getSemesters(student).toSingle(emptyList()) })
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ class StudentLocal @Inject constructor(
|
||||
return Completable.fromCallable {
|
||||
studentDb.run {
|
||||
resetCurrent()
|
||||
updateCurrent(student.studentId)
|
||||
updateCurrent(student.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ class StudentRemote @Inject constructor(private val api: Api) {
|
||||
studentName = student.studentName,
|
||||
schoolSymbol = student.schoolSymbol,
|
||||
schoolName = student.schoolName,
|
||||
className = student.className,
|
||||
classId = student.classId,
|
||||
endpoint = endpoint,
|
||||
loginType = student.loginType.name,
|
||||
isCurrent = false,
|
||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
@ -36,7 +37,7 @@ class StudentRepository @Inject constructor(
|
||||
|
||||
fun getCurrentStudent(decryptPass: Boolean = true): Single<Student> {
|
||||
return local.getCurrentStudent(decryptPass)
|
||||
.switchIfEmpty(Maybe.error(NoSuchElementException("No current student")))
|
||||
.switchIfEmpty(Maybe.error(NoCurrentStudentException()))
|
||||
.toSingle()
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package io.github.wulkanowy.di
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import io.github.wulkanowy.di.scopes.PerActivity
|
||||
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.login.LoginModule
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
@ -30,9 +29,6 @@ internal abstract class BuilderModule {
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindMessageSendActivity(): SendMessageActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindTimetableWidgetService(): TimetableWidgetService
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import com.squareup.inject.assisted.dagger2.AssistedModule
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import dagger.multibindings.IntoSet
|
||||
import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork
|
||||
import io.github.wulkanowy.services.sync.works.AttendanceWork
|
||||
@ -24,6 +25,7 @@ import io.github.wulkanowy.services.sync.works.NoteWork
|
||||
import io.github.wulkanowy.services.sync.works.RecipientWork
|
||||
import io.github.wulkanowy.services.sync.works.TimetableWork
|
||||
import io.github.wulkanowy.services.sync.works.Work
|
||||
import io.github.wulkanowy.services.widgets.TimetableWidgetService
|
||||
import javax.inject.Singleton
|
||||
|
||||
@AssistedModule
|
||||
@ -48,6 +50,9 @@ abstract class ServicesModule {
|
||||
fun provideNotificationManager(context: Context) = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
}
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun bindTimetableWidgetService(): TimetableWidgetService
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun provideGradeWork(work: GradeWork): Work
|
||||
|
@ -40,7 +40,7 @@ class SyncManager @Inject constructor(
|
||||
fun startSyncWorker(restart: Boolean = false) {
|
||||
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
|
||||
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
|
||||
PeriodicWorkRequest.Builder(SyncWorker::class.java, preferencesRepository.servicesInterval, MINUTES)
|
||||
PeriodicWorkRequest.Builder(SyncWorker::class.java, preferencesRepository.servicesInterval, MINUTES, 10, MINUTES)
|
||||
.setBackoffCriteria(EXPONENTIAL, 30, MINUTES)
|
||||
.setConstraints(Constraints.Builder()
|
||||
.setRequiredNetworkType(if (preferencesRepository.isServicesOnlyWifi) METERED else UNMETERED)
|
||||
|
@ -11,6 +11,7 @@ import androidx.work.WorkerParameters
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.api.interceptor.FeatureDisabledException
|
||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
@ -33,19 +34,31 @@ class SyncWorker @AssistedInject constructor(
|
||||
) : RxWorker(appContext, workerParameters) {
|
||||
|
||||
override fun createWork(): Single<Result> {
|
||||
return studentRepository.getCurrentStudent()
|
||||
Timber.i("SyncWorker is starting")
|
||||
return studentRepository.isStudentSaved()
|
||||
.filter { true }
|
||||
.flatMap { studentRepository.getCurrentStudent().toMaybe() }
|
||||
.flatMapCompletable { student ->
|
||||
semesterRepository.getCurrentSemester(student, true)
|
||||
.flatMapCompletable { semester ->
|
||||
Completable.mergeDelayError(works.map { it.create(student, semester) })
|
||||
Completable.mergeDelayError(works.map { work ->
|
||||
work.create(student, semester)
|
||||
.doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") }
|
||||
.doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") }
|
||||
.doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") }
|
||||
})
|
||||
}
|
||||
}
|
||||
.toSingleDefault(Result.success())
|
||||
.onErrorReturn {
|
||||
Timber.e(it, "There was an error during synchronization")
|
||||
Result.retry()
|
||||
if (it is FeatureDisabledException) Result.success()
|
||||
else Result.retry()
|
||||
}
|
||||
.doOnSuccess {
|
||||
if (preferencesRepository.isDebugNotificationEnable) notify(it)
|
||||
Timber.i("SyncWorker result: $it")
|
||||
}
|
||||
.doOnSuccess { if (preferencesRepository.isDebugNotificationEnable) notify(it) }
|
||||
}
|
||||
|
||||
private fun notify(result: Result) {
|
||||
|
@ -13,10 +13,10 @@ class RecipientWork @Inject constructor(
|
||||
) : Work {
|
||||
|
||||
override fun create(student: Student, semester: Semester): Completable {
|
||||
return reportingUnitRepository.getReportingUnits(student)
|
||||
return reportingUnitRepository.getReportingUnits(student, true)
|
||||
.flatMapCompletable { units ->
|
||||
Completable.mergeDelayError(units.map {
|
||||
recipientRepository.getRecipients(student, 2, it).ignoreElement()
|
||||
recipientRepository.getRecipients(student, 2, it, true).ignoreElement()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package io.github.wulkanowy.ui.base.session
|
||||
|
||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||
|
||||
open class BaseSessionFragment : BaseFragment(), BaseSessionView {
|
||||
@ -8,4 +11,11 @@ open class BaseSessionFragment : BaseFragment(), BaseSessionView {
|
||||
override fun showExpiredDialog() {
|
||||
(activity as? MainActivity)?.showExpiredDialog()
|
||||
}
|
||||
|
||||
override fun openLoginView() {
|
||||
activity?.also {
|
||||
startActivity(LoginActivity.getStartIntent(it)
|
||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ open class BaseSessionPresenter<T : BaseSessionView>(private val errorHandler: S
|
||||
|
||||
override fun onAttachView(view: T) {
|
||||
super.onAttachView(view)
|
||||
errorHandler.onDecryptionFail = { view.showExpiredDialog() }
|
||||
errorHandler.apply {
|
||||
onDecryptionFail = { view.showExpiredDialog() }
|
||||
onNoCurrentStudent = { view.openLoginView() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,4 +5,6 @@ import io.github.wulkanowy.ui.base.BaseView
|
||||
interface BaseSessionView : BaseView {
|
||||
|
||||
fun showExpiredDialog()
|
||||
|
||||
fun openLoginView()
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.base.session
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
||||
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||
import io.github.wulkanowy.utils.security.ScramblerException
|
||||
import javax.inject.Inject
|
||||
@ -13,9 +14,12 @@ open class SessionErrorHandler @Inject constructor(
|
||||
|
||||
var onDecryptionFail: () -> Unit = {}
|
||||
|
||||
var onNoCurrentStudent: () -> Unit = {}
|
||||
|
||||
override fun proceed(error: Throwable) {
|
||||
when (error) {
|
||||
is ScramblerException -> onDecryptionFail()
|
||||
is NoCurrentStudentException -> onNoCurrentStudent()
|
||||
else -> super.proceed(error)
|
||||
}
|
||||
}
|
||||
@ -23,5 +27,6 @@ open class SessionErrorHandler @Inject constructor(
|
||||
override fun clear() {
|
||||
super.clear()
|
||||
onDecryptionFail = {}
|
||||
onNoCurrentStudent = {}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
||||
.withAboutSpecial3(getString(R.string.about_feedback))
|
||||
.withFields(R.string::class.java.fields)
|
||||
.withCheckCachedDetection(false)
|
||||
.withExcludedLibraries("fastadapter", "AndroidIconics", "gson", "Jsoup", "Retrofit", "okio", "OkHttp")
|
||||
.withExcludedLibraries("fastadapter", "AndroidIconics", "Jsoup", "Retrofit", "okio",
|
||||
"OkHttp", "Butterknife", "CircleImageView")
|
||||
.withOnExtraListener { presenter.onExtraSelect(it) })
|
||||
}.let {
|
||||
fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it)
|
||||
@ -68,7 +69,7 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
||||
data = Uri.parse("mailto:")
|
||||
putExtra(Intent.EXTRA_EMAIL, Array(1) { "wulkanowyinc@gmail.com" })
|
||||
putExtra(Intent.EXTRA_SUBJECT, "Zgłoszenie błędu")
|
||||
putExtra(Intent.EXTRA_TEXT,"Tu umieść treść zgłoszenia\n\n" + "-".repeat(40) + "\n" + """
|
||||
putExtra(Intent.EXTRA_TEXT, "Tu umieść treść zgłoszenia\n\n" + "-".repeat(40) + "\n" + """
|
||||
Build: ${BuildConfig.VERSION_CODE}
|
||||
SDK: ${android.os.Build.VERSION.SDK_INT}
|
||||
Device: ${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
@ -14,13 +15,14 @@ class AccountItem(val student: Student) : AbstractFlexibleItem<AccountItem.ViewH
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_account
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.apply {
|
||||
accountItemName.text = student.studentName
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
accountItemName.text = "${student.studentName} ${student.className}"
|
||||
accountItemSchool.text = student.schoolName
|
||||
accountItemImage.setBackgroundResource(if (student.isCurrent) R.drawable.ic_account_circular_border else 0)
|
||||
}
|
||||
@ -38,14 +40,13 @@ class AccountItem(val student: Student) : AbstractFlexibleItem<AccountItem.ViewH
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return student.hashCode()
|
||||
var result = student.hashCode()
|
||||
result = 31 * result + student.id.toInt()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,14 +14,13 @@ import kotlinx.android.synthetic.main.item_attendance.*
|
||||
|
||||
class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem<AttendanceItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_attendance
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_attendance
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
attendanceItemNumber.text = attendance.number.toString()
|
||||
attendanceItemSubject.text = attendance.subject
|
||||
@ -37,16 +36,17 @@ class AttendanceItem(val attendance: Attendance) : AbstractFlexibleItem<Attendan
|
||||
other as AttendanceItem
|
||||
|
||||
if (attendance != other.attendance) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return attendance.hashCode()
|
||||
var result = attendance.hashCode()
|
||||
result = 31 * result + attendance.id.toInt()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ class AttendancePresenter @Inject constructor(
|
||||
clearData()
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,12 @@ class AttendanceSummaryItem(
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_attendance_summary
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.apply {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
attendanceSummaryMonth.text = month
|
||||
attendanceSummaryPercentage.text = percentage
|
||||
attendanceSummaryPresent.text = present
|
||||
@ -73,10 +73,8 @@ class AttendanceSummaryItem(
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem<Exa
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
examItemSubject.text = exam.subject
|
||||
examItemTeacher.text = exam.teacher
|
||||
@ -39,12 +38,12 @@ class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem<Exa
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return exam.hashCode()
|
||||
var result = exam.hashCode()
|
||||
result = 31 * result + exam.id.toInt()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
||||
@Inject
|
||||
lateinit var pagerAdapter: BaseFragmentPagerAdapter
|
||||
|
||||
private var semesterSwitchMenu: MenuItem? = null
|
||||
|
||||
companion object {
|
||||
private const val SAVED_SEMESTER_KEY = "CURRENT_SEMESTER"
|
||||
|
||||
@ -57,6 +59,8 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
inflater?.inflate(R.menu.action_menu_grade, menu)
|
||||
semesterSwitchMenu = menu?.findItem(R.id.gradeMenuSemester)
|
||||
presenter.onCreateMenu()
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
@ -75,6 +79,7 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
||||
setOnSelectPageListener { presenter.onPageSelected(it) }
|
||||
}
|
||||
gradeTabLayout.setupWithViewPager(gradeViewPager)
|
||||
gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
@ -95,8 +100,20 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
||||
gradeProgress.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showEmpty() {
|
||||
gradeEmpty.visibility = VISIBLE
|
||||
override fun showEmpty(show: Boolean) {
|
||||
gradeEmpty.visibility = if (show) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
override fun showRefresh(show: Boolean) {
|
||||
gradeSwipe.isRefreshing = show
|
||||
}
|
||||
|
||||
override fun showSemesterSwitch(show: Boolean) {
|
||||
semesterSwitchMenu?.isVisible = show
|
||||
}
|
||||
|
||||
override fun enableSwipe(enable: Boolean) {
|
||||
gradeSwipe.isEnabled = enable
|
||||
}
|
||||
|
||||
override fun showSemesterDialog(selectedIndex: Int) {
|
||||
|
@ -7,9 +7,7 @@ import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.reactivex.Completable
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import javax.inject.Inject
|
||||
|
||||
class GradePresenter @Inject constructor(
|
||||
@ -30,12 +28,16 @@ class GradePresenter @Inject constructor(
|
||||
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
||||
super.onAttachView(view)
|
||||
Timber.i("Grade view is attached")
|
||||
disposable.add(Completable.timer(150, MILLISECONDS, schedulers.mainThread)
|
||||
.subscribe {
|
||||
selectedIndex = savedIndex ?: 0
|
||||
view.initView()
|
||||
loadData()
|
||||
})
|
||||
selectedIndex = savedIndex ?: 0
|
||||
view.run {
|
||||
initView()
|
||||
enableSwipe(false)
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
|
||||
fun onCreateMenu() {
|
||||
if (semesters.isEmpty()) view?.showSemesterSwitch(false)
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
@ -69,12 +71,17 @@ class GradePresenter @Inject constructor(
|
||||
view?.apply {
|
||||
showContent(true)
|
||||
showProgress(false)
|
||||
showEmpty(false)
|
||||
loadedSemesterId[currentPageIndex] = semesterId
|
||||
}
|
||||
}
|
||||
|
||||
fun onPageSelected(index: Int) {
|
||||
loadChild(index)
|
||||
if (semesters.isNotEmpty()) loadChild(index)
|
||||
}
|
||||
|
||||
fun onSwipeRefresh() {
|
||||
loadData()
|
||||
}
|
||||
|
||||
private fun loadData() {
|
||||
@ -89,17 +96,21 @@ class GradePresenter @Inject constructor(
|
||||
}
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doFinally { view?.showRefresh(false) }
|
||||
.subscribe({
|
||||
view?.run {
|
||||
Timber.i("Loading grade result: Attempt load index $currentPageIndex")
|
||||
loadChild(currentPageIndex)
|
||||
enableSwipe(false)
|
||||
showSemesterSwitch(true)
|
||||
}
|
||||
}) {
|
||||
Timber.i("Loading grade result: An exception occurred")
|
||||
errorHandler.dispatch(it)
|
||||
view?.run {
|
||||
showProgress(false)
|
||||
showEmpty()
|
||||
showEmpty(true)
|
||||
enableSwipe(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -12,10 +12,16 @@ interface GradeView : BaseSessionView {
|
||||
|
||||
fun showProgress(show: Boolean)
|
||||
|
||||
fun showEmpty()
|
||||
fun showEmpty(show: Boolean)
|
||||
|
||||
fun showRefresh(show: Boolean)
|
||||
|
||||
fun showSemesterSwitch(show: Boolean)
|
||||
|
||||
fun showSemesterDialog(selectedIndex: Int)
|
||||
|
||||
fun enableSwipe(enable: Boolean)
|
||||
|
||||
fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean)
|
||||
|
||||
fun notifyChildParentReselected(index: Int)
|
||||
|
@ -28,10 +28,7 @@ class GradeDetailsItem(
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?
|
||||
) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
gradeItemValue.run {
|
||||
text = grade.entry
|
||||
@ -70,9 +67,7 @@ class GradeDetailsItem(
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onSubjectSelected(name: String) {
|
||||
Timber.i("Select attendance stats subject $name")
|
||||
Timber.i("Select grade stats subject $name")
|
||||
view?.run {
|
||||
showContent(false)
|
||||
showProgress(true)
|
||||
@ -77,7 +77,7 @@ class GradeStatisticsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onTypeChange(isSemester: Boolean) {
|
||||
Timber.i("Select attendance stats semester: $isSemester")
|
||||
Timber.i("Select grade stats semester: $isSemester")
|
||||
disposable.clear()
|
||||
view?.run {
|
||||
showContent(false)
|
||||
|
@ -18,15 +18,12 @@ class GradeSummaryItem(
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_grade_summary
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?,
|
||||
position: Int, payloads: MutableList<Any>?
|
||||
) {
|
||||
holder?.run {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
gradeSummaryItemTitle.text = title
|
||||
gradeSummaryItemAverage.text = average
|
||||
gradeSummaryItemPredicted.text = predictedGrade
|
||||
@ -56,10 +53,8 @@ class GradeSummaryItem(
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,8 @@ import io.github.wulkanowy.data.db.entities.Homework
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_homework.*
|
||||
|
||||
class HomeworkItem(
|
||||
header: HomeworkHeader, val homework: Homework
|
||||
) : AbstractSectionableItem<HomeworkItem.ViewHolder, HomeworkHeader>(header) {
|
||||
class HomeworkItem(header: HomeworkHeader, val homework: Homework) :
|
||||
AbstractSectionableItem<HomeworkItem.ViewHolder, HomeworkHeader>(header) {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_homework
|
||||
|
||||
@ -20,10 +19,7 @@ class HomeworkItem(
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?
|
||||
) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
homeworkItemSubject.text = homework.subject
|
||||
homeworkItemTeacher.text = homework.teacher
|
||||
@ -42,12 +38,12 @@ class HomeworkItem(
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return homework.hashCode()
|
||||
var result = homework.hashCode()
|
||||
result = 31 * result + homework.id.toInt()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.View
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
@ -8,19 +9,22 @@ import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_login_student_select.view.*
|
||||
import kotlinx.android.synthetic.main.item_login_student_select.*
|
||||
|
||||
class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem<LoginStudentSelectItem.ItemViewHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_login_student_select
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ItemViewHolder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ItemViewHolder {
|
||||
return ItemViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ItemViewHolder?,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.bind(student)
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ItemViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.run {
|
||||
loginItemName.text = "${student.studentName} ${student.className}"
|
||||
loginItemSchool.text = student.schoolName
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@ -38,17 +42,8 @@ class LoginStudentSelectItem(val student: Student) : AbstractFlexibleItem<LoginS
|
||||
return student.hashCode()
|
||||
}
|
||||
|
||||
class ItemViewHolder(view: View?, adapter: FlexibleAdapter<*>?)
|
||||
: FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
class ItemViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = itemView
|
||||
|
||||
fun bind(item: Student) {
|
||||
itemView.run {
|
||||
loginItemName.text = item.studentName
|
||||
loginItemSchool.text = item.schoolName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,11 @@ class LuckyNumberPresenter @Inject constructor(
|
||||
override fun onAttachView(view: LuckyNumberView) {
|
||||
super.onAttachView(view)
|
||||
Timber.i("Lucky number view is attached")
|
||||
view.initView()
|
||||
view.run {
|
||||
initView()
|
||||
showContent(false)
|
||||
enableSwipe(false)
|
||||
}
|
||||
loadData()
|
||||
}
|
||||
|
||||
@ -35,12 +39,6 @@ class LuckyNumberPresenter @Inject constructor(
|
||||
.flatMapMaybe { luckyNumberRepository.getLuckyNumber(it, forceRefresh) }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doOnSubscribe {
|
||||
view?.run {
|
||||
showContent(false)
|
||||
enableSwipe(false)
|
||||
}
|
||||
}
|
||||
.doFinally {
|
||||
view?.run {
|
||||
hideRefresh()
|
||||
|
@ -2,7 +2,10 @@ package io.github.wulkanowy.ui.modules.main
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
@ -68,11 +71,6 @@ class MainActivity : BaseActivity(), MainView {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
presenter.onViewChange()
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
mainBottomNav.run {
|
||||
addItems(
|
||||
@ -144,7 +142,9 @@ class MainActivity : BaseActivity(), MainView {
|
||||
}
|
||||
|
||||
override fun notifyMenuViewReselected() {
|
||||
(navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected()
|
||||
Handler().postDelayed({
|
||||
(navController.currentStack?.get(0) as? MainView.MainChildView)?.onFragmentReselected()
|
||||
}, 250)
|
||||
}
|
||||
|
||||
fun showDialogFragment(dialog: DialogFragment) {
|
||||
@ -165,7 +165,7 @@ class MainActivity : BaseActivity(), MainView {
|
||||
|
||||
override fun openLoginView() {
|
||||
startActivity(LoginActivity.getStartIntent(this)
|
||||
.apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle?) {
|
||||
|
@ -5,7 +5,6 @@ import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.di.scopes.PerActivity
|
||||
import io.github.wulkanowy.di.scopes.PerFragment
|
||||
import io.github.wulkanowy.ui.modules.about.AboutFragment
|
||||
import io.github.wulkanowy.ui.modules.about.AboutModule
|
||||
@ -33,7 +32,6 @@ abstract class MainModule {
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
@PerActivity
|
||||
@Provides
|
||||
fun provideFragNavController(activity: MainActivity): FragNavController {
|
||||
return FragNavController(activity.supportFragmentManager, R.id.mainFragmentContainer)
|
||||
|
@ -24,9 +24,9 @@ class MainPresenter @Inject constructor(
|
||||
|
||||
fun onAttachView(view: MainView, initMenuIndex: Int) {
|
||||
super.onAttachView(view)
|
||||
Timber.i("Main view is attached with $initMenuIndex menu index")
|
||||
view.run {
|
||||
startMenuIndex = if (initMenuIndex != -1) initMenuIndex else prefRepository.startMenuIndex
|
||||
Timber.i("Main view is attached with $startMenuIndex menu index")
|
||||
initView()
|
||||
}
|
||||
|
||||
|
@ -20,12 +20,9 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_message
|
||||
override fun getLayoutRes() = R.layout.item_message
|
||||
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?
|
||||
) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
val style = if (message.unread) BOLD else NORMAL
|
||||
|
||||
@ -58,9 +55,7 @@ class MessageItem(val message: Message, private val noSubjectString: String) :
|
||||
return message.hashCode()
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -72,6 +72,10 @@ class SendMessageActivity : BaseActivity(), SendMessageView {
|
||||
else false
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
return presenter.onUpNavigate()
|
||||
}
|
||||
|
||||
override fun setReportingUnit(unit: ReportingUnit) {
|
||||
sendMessageFromTextView.setText(unit.senderName)
|
||||
}
|
||||
|
@ -47,6 +47,11 @@ class SendMessagePresenter @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun onUpNavigate(): Boolean {
|
||||
view?.popView()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun loadData(message: Message?) {
|
||||
var reportingUnit: ReportingUnit? = null
|
||||
var recipients: List<Recipient> = emptyList()
|
||||
|
@ -14,12 +14,12 @@ class MoreItem(val title: String, private val drawable: Drawable?) : AbstractFle
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_more
|
||||
|
||||
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>>?): ViewHolder {
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>?, holder: ViewHolder?, position: Int, payloads: MutableList<Any>?) {
|
||||
holder?.apply {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
moreItemTitle.text = title
|
||||
moreItemImage.setImageDrawable(drawable)
|
||||
}
|
||||
@ -40,9 +40,8 @@ class MoreItem(val title: String, private val drawable: Drawable?) : AbstractFle
|
||||
return title.hashCode()
|
||||
}
|
||||
|
||||
class ViewHolder(view: View?, adapter: FlexibleAdapter<*>?) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
|
||||
override val containerView: View?
|
||||
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
}
|
||||
|
@ -15,16 +15,13 @@ import kotlinx.android.synthetic.main.item_note.*
|
||||
|
||||
class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes() = R.layout.item_note
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): NoteItem.ViewHolder {
|
||||
return NoteItem.ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_note
|
||||
|
||||
override fun bindViewHolder(
|
||||
adapter: FlexibleAdapter<IFlexible<*>>,
|
||||
holder: NoteItem.ViewHolder, position: Int, payloads: MutableList<Any>?
|
||||
) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: NoteItem.ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
noteItemDate.apply {
|
||||
text = note.date.toFormattedString()
|
||||
@ -57,7 +54,6 @@ class NoteItem(val note: Note) : AbstractFlexibleItem<NoteItem.ViewHolder>() {
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -15,18 +15,17 @@ import io.github.wulkanowy.utils.toFormattedString
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.item_timetable.*
|
||||
|
||||
class TimetableItem(val lesson: Timetable, private val roomText: String)
|
||||
: AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||
class TimetableItem(val lesson: Timetable, private val roomText: String) :
|
||||
AbstractFlexibleItem<TimetableItem.ViewHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int = R.layout.item_timetable
|
||||
override fun getLayoutRes() = R.layout.item_timetable
|
||||
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<*>>): ViewHolder {
|
||||
return ViewHolder(view, adapter)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder,
|
||||
position: Int, payloads: MutableList<Any>?) {
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<*>>, holder: ViewHolder, position: Int, payloads: MutableList<Any>?) {
|
||||
holder.apply {
|
||||
timetableItemNumber.text = lesson.number.toString()
|
||||
timetableItemSubject.text = lesson.subject
|
||||
@ -34,8 +33,8 @@ class TimetableItem(val lesson: Timetable, private val roomText: String)
|
||||
timetableItemTime.text = "${lesson.start.toFormattedString("HH:mm")} - ${lesson.end.toFormattedString("HH:mm")}"
|
||||
timetableItemAlert.visibility = if (lesson.changes || lesson.canceled) VISIBLE else GONE
|
||||
timetableItemSubject.paintFlags =
|
||||
if (lesson.canceled) timetableItemSubject.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else timetableItemSubject.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
if (lesson.canceled) timetableItemSubject.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
||||
else timetableItemSubject.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,12 +49,12 @@ class TimetableItem(val lesson: Timetable, private val roomText: String)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return lesson.hashCode()
|
||||
var result = lesson.hashCode()
|
||||
result = 31 * result + lesson.id.toInt()
|
||||
return result
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter),
|
||||
LayoutContainer {
|
||||
|
||||
class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
||||
override val containerView: View
|
||||
get() = contentView
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ class TimetablePresenter @Inject constructor(
|
||||
clearData()
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ class CompletedLessonsPresenter @Inject constructor(
|
||||
clearData()
|
||||
showNextButton(!currentDate.plusDays(1).isHolidays)
|
||||
showPreButton(!currentDate.minusDays(1).isHolidays)
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE \n dd.MM.YYYY").capitalize())
|
||||
updateNavigationDay(currentDate.toFormattedString("EEEE\ndd.MM.YYYY").capitalize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||
import io.github.wulkanowy.utils.SchedulersProvider
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import io.reactivex.Single
|
||||
import org.threeten.bp.LocalDate
|
||||
import timber.log.Timber
|
||||
|
||||
@ -51,9 +52,13 @@ class TimetableWidgetFactory(
|
||||
?.let { date ->
|
||||
try {
|
||||
lessons = studentRepository.isStudentSaved()
|
||||
.flatMap { studentRepository.getCurrentStudent() }
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { timetableRepository.getTimetable(it, date, date) }
|
||||
.flatMap { isSaved ->
|
||||
if (isSaved) {
|
||||
studentRepository.getCurrentStudent()
|
||||
.flatMap { semesterRepository.getCurrentSemester(it) }
|
||||
.flatMap { timetableRepository.getTimetable(it, date, date) }
|
||||
} else Single.just(emptyList())
|
||||
}
|
||||
.map { item -> item.sortedBy { it.number } }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.blockingGet()
|
||||
|
@ -62,7 +62,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
|
||||
private fun onUpdate(context: Context, intent: Intent) {
|
||||
if (intent.getStringExtra(EXTRA_BUTTON_TYPE) === null) {
|
||||
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS).forEach { appWidgetId ->
|
||||
intent.getIntArrayExtra(EXTRA_APPWIDGET_IDS)?.forEach { appWidgetId ->
|
||||
updateWidget(context, appWidgetId, now().nextOrSameSchoolDay)
|
||||
}
|
||||
} else {
|
||||
@ -95,7 +95,7 @@ class TimetableWidgetProvider : BroadcastReceiver() {
|
||||
.apply { action = createWidgetKey(appWidgetId) })
|
||||
setOnClickPendingIntent(R.id.timetableWidgetNext, createNavIntent(context, appWidgetId, appWidgetId, BUTTON_NEXT))
|
||||
setOnClickPendingIntent(R.id.timetableWidgetPrev, createNavIntent(context, -appWidgetId, appWidgetId, BUTTON_PREV))
|
||||
createNavIntent(context, Int.MAX_VALUE, appWidgetId, BUTTON_RESET).also {
|
||||
createNavIntent(context, Int.MAX_VALUE - appWidgetId, appWidgetId, BUTTON_RESET).also {
|
||||
setOnClickPendingIntent(R.id.timetableWidgetDate, it)
|
||||
setOnClickPendingIntent(R.id.timetableWidgetDay, it)
|
||||
}
|
||||
|
@ -1,20 +1,9 @@
|
||||
Wersja 0.7.0
|
||||
|
||||
Dodaliśmy:
|
||||
- szczęśliwy numerek
|
||||
- lekcje zrealizowane
|
||||
- wysyłanie wiadomości
|
||||
- ucznia na tle klasy
|
||||
- opcję zmiany kolorów ocen
|
||||
|
||||
Zmieniliśmy:
|
||||
- wygląd ekranu logowania
|
||||
- sposób wyświetlania zastępstw
|
||||
- widok zadań domowych na tygodniowy
|
||||
Wersja 0.7.5
|
||||
|
||||
Naprawiliśmy:
|
||||
- automatyczne przełączanie widżetu na nowy dzień
|
||||
- wyświetlanie powiadomień o starych ocenach
|
||||
- znikające numery sal w planie lekcji
|
||||
- problem z brakiem aktywnego semestru (jeśli doświadczysz jakichś problemów - wyloguj i zaloguj się ponownie)
|
||||
- logowanie w niestandardowych dziennikach na vulcan.net.pl
|
||||
- oznaczanie lekcji w planie jako odwołanej, jeśli brak opisu tej zmiany
|
||||
- ładowanie wiadomości, jeśli byli zalogowani jednocześnie uczeń i rodzic
|
||||
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.7.0
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases/tag/0.7.5
|
||||
|
@ -1,4 +1,5 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@null" />
|
||||
<stroke
|
||||
android:width="1dip"
|
||||
android:color="#61000000" />
|
||||
|
@ -17,13 +17,19 @@
|
||||
app:tabTextColor="@android:color/white"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/gradeViewPager"
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/gradeSwipe"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="48dp"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
android:layout_marginTop="48dp">
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/gradeViewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"
|
||||
tools:visibility="visible" />
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/gradeProgress"
|
||||
|
@ -30,8 +30,10 @@
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_toEndOf="@id/accountItemImage"
|
||||
android:layout_toRightOf="@id/accountItemImage"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="16sp" />
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textSize="16sp"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/accountItemSchool"
|
||||
@ -45,6 +47,6 @@
|
||||
android:layout_toRightOf="@id/accountItemImage"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="12sp"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
</RelativeLayout>
|
||||
|
@ -22,6 +22,7 @@
|
||||
<item>0,25</item>
|
||||
<item>0,33</item>
|
||||
<item>0,5</item>
|
||||
<item>0,75</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="grade_color_scheme_entries">
|
||||
|
@ -50,12 +50,14 @@
|
||||
<item>0,25</item>
|
||||
<item>0,33</item>
|
||||
<item>0,5</item>
|
||||
<item>0,75</item>
|
||||
</string-array>
|
||||
<string-array name="grade_modifier_value" translatable="false">
|
||||
<item>0.0</item>
|
||||
<item>0.25</item>
|
||||
<item>0.33</item>
|
||||
<item>0.5</item>
|
||||
<item>0.75</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="grade_color_scheme_entries">
|
||||
|
@ -0,0 +1,19 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
class UnitTestInternetObservingStrategy : InternetObservingStrategy {
|
||||
|
||||
override fun checkInternetConnectivity(host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Single<Boolean> {
|
||||
return Single.just(true)
|
||||
}
|
||||
|
||||
override fun observeInternetConnectivity(initialIntervalInMs: Int, intervalInMs: Int, host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Observable<Boolean> {
|
||||
return Observable.just(true)
|
||||
}
|
||||
|
||||
override fun getDefaultPingHost() = "localhost"
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.attendance
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.attendance.Attendance
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.attendance.AttendanceRemote
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
@ -1,9 +1,8 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.completedlessons
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.timetable.CompletedLesson
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.completedlessons.CompletedLessonsRemote
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
@ -1,9 +1,8 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.exam
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.exams.Exam
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.exam.ExamRemote
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
@ -1,9 +1,8 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.gradestatistics
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.grades.GradeStatistics
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.repositories.gradestatistics.GradeStatisticsRemote
|
||||
import io.mockk.MockKAnnotations
|
||||
import io.mockk.every
|
||||
import io.mockk.impl.annotations.MockK
|
@ -1,4 +1,4 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.luckynumber
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
@ -0,0 +1,74 @@
|
||||
package io.github.wulkanowy.data.repositories.semester
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||
import io.github.wulkanowy.data.ApiHelper
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.repositories.UnitTestInternetObservingStrategy
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.doNothing
|
||||
import org.mockito.Mockito.doReturn
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class SemesterRepositoryTest {
|
||||
|
||||
@Mock
|
||||
private lateinit var semesterRemote: SemesterRemote
|
||||
|
||||
@Mock
|
||||
private lateinit var semesterLocal: SemesterLocal
|
||||
|
||||
@Mock
|
||||
private lateinit var apiHelper: ApiHelper
|
||||
|
||||
@Mock
|
||||
private lateinit var student: Student
|
||||
|
||||
private lateinit var semesterRepository: SemesterRepository
|
||||
|
||||
private val settings = InternetObservingSettings.builder()
|
||||
.strategy(UnitTestInternetObservingStrategy())
|
||||
.build()
|
||||
|
||||
@Before
|
||||
fun initTest() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
semesterRepository = SemesterRepository(semesterRemote, semesterLocal, settings, apiHelper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun singleCurrentSemesterTest() {
|
||||
val semesters = listOf(
|
||||
createSemesterEntity(false),
|
||||
createSemesterEntity(true)
|
||||
)
|
||||
|
||||
doNothing().`when`(apiHelper).initApi(student)
|
||||
doReturn(Maybe.empty<Semester>()).`when`(semesterLocal).getSemesters(student)
|
||||
doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student)
|
||||
|
||||
semesterRepository.getSemesters(student).blockingGet()
|
||||
|
||||
verify(semesterLocal).deleteSemesters(emptyList())
|
||||
verify(semesterLocal).saveSemesters(semesters)
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun twoCurrentSemesterTest() {
|
||||
val semesters = listOf(
|
||||
createSemesterEntity(true),
|
||||
createSemesterEntity(true)
|
||||
)
|
||||
|
||||
doNothing().`when`(apiHelper).initApi(student)
|
||||
doReturn(Maybe.empty<Semester>()).`when`(semesterLocal).getSemesters(student)
|
||||
doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student)
|
||||
|
||||
semesterRepository.getSemesters(student).blockingGet()
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package io.github.wulkanowy.data.repositories.semester
|
||||
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import org.threeten.bp.LocalDate.now
|
||||
|
||||
fun createSemesterEntity(current: Boolean): Semester {
|
||||
return Semester(
|
||||
studentId = 0,
|
||||
diaryId = 0,
|
||||
semesterId = 0,
|
||||
diaryName = "",
|
||||
schoolYear = 1970,
|
||||
classId = 0,
|
||||
isCurrent = current,
|
||||
semesterName = 0,
|
||||
unitId = 0,
|
||||
start = now(),
|
||||
end = now()
|
||||
)
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.student
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.register.Student
|
||||
import io.github.wulkanowy.data.repositories.student.StudentRemote
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
@ -23,7 +22,7 @@ class StudentRemoteTest {
|
||||
|
||||
@Test
|
||||
fun testRemoteAll() {
|
||||
doReturn(Single.just(listOf(Student("", "", 1, "test", "", "", Api.LoginType.AUTO))))
|
||||
doReturn(Single.just(listOf(Student("", "", 1, "test", "", "", "", 1, Api.LoginType.AUTO))))
|
||||
.`when`(mockApi).getStudents()
|
||||
|
||||
val students = StudentRemote(mockApi).getStudents("", "", "").blockingGet()
|
@ -1,4 +1,4 @@
|
||||
package io.github.wulkanowy.data.repositories.remote
|
||||
package io.github.wulkanowy.data.repositories.timetable
|
||||
|
||||
import io.github.wulkanowy.api.Api
|
||||
import io.github.wulkanowy.api.timetable.Timetable
|
@ -86,7 +86,7 @@ class LoginFormPresenterTest {
|
||||
|
||||
@Test
|
||||
fun loginTest() {
|
||||
val studentTest = Student(email = "test@", password = "123", endpoint = "https://fakelog.cf", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, isCurrent = false, symbol = "", registrationDate = now())
|
||||
val studentTest = Student(email = "test@", password = "123", endpoint = "https://fakelog.cf", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "")
|
||||
doReturn(Single.just(listOf(studentTest)))
|
||||
.`when`(repository).getStudents(anyString(), anyString(), anyString(), anyString())
|
||||
|
||||
|
@ -32,7 +32,7 @@ class LoginStudentSelectPresenterTest {
|
||||
|
||||
private lateinit var presenter: LoginStudentSelectPresenter
|
||||
|
||||
private val testStudent by lazy { Student(email = "test", password = "test123", endpoint = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", studentName = "", registrationDate = now()) }
|
||||
private val testStudent by lazy { Student(email = "test", password = "test123", endpoint = "https://fakelog.cf", loginType = "AUTO", symbol = "", isCurrent = false, studentId = 0, schoolName = "", schoolSymbol = "", classId = 1, studentName = "", registrationDate = now(), className = "") }
|
||||
|
||||
private val testException by lazy { RuntimeException("Problem") }
|
||||
|
||||
|
@ -22,11 +22,11 @@ class GradeExtensionTest {
|
||||
@Test
|
||||
fun calcWeightedAverage() {
|
||||
assertEquals(3.47, listOf(
|
||||
createGrade(5, 6, 0.33),
|
||||
createGrade(5, 5, -0.33),
|
||||
createGrade(4, 1, 0.0),
|
||||
createGrade(1, 9, 0.5),
|
||||
createGrade(0, 0, 0.0)
|
||||
createGrade(5, 6.0, 0.33),
|
||||
createGrade(5, 5.0, -0.33),
|
||||
createGrade(4, 1.0, 0.0),
|
||||
createGrade(1, 9.0, 0.5),
|
||||
createGrade(0, .0, 0.0)
|
||||
).calcAverage(), 0.005)
|
||||
}
|
||||
|
||||
@ -42,23 +42,23 @@ class GradeExtensionTest {
|
||||
|
||||
@Test
|
||||
fun changeModifier_default() {
|
||||
assertEquals(.33, createGrade(5, 0, .33).changeModifier(.0, .0).modifier, .0)
|
||||
assertEquals(-.33, createGrade(5, 0, -.33).changeModifier(.0, .0).modifier, .0)
|
||||
assertEquals(.33, createGrade(5, .0, .33).changeModifier(.0, .0).modifier, .0)
|
||||
assertEquals(-.33, createGrade(5, .0, -.33).changeModifier(.0, .0).modifier, .0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun changeModifier_plus() {
|
||||
assertEquals(.33, createGrade(5, 0, .25).changeModifier(.33, .50).modifier, .0)
|
||||
assertEquals(.25, createGrade(5, 0, .33).changeModifier(.25, .0).modifier, .0)
|
||||
assertEquals(.33, createGrade(5, .0, .25).changeModifier(.33, .50).modifier, .0)
|
||||
assertEquals(.25, createGrade(5, .0, .33).changeModifier(.25, .0).modifier, .0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun changeModifier_minus() {
|
||||
assertEquals(-.33, createGrade(5, 0, -.25).changeModifier(.25, .33).modifier, .0)
|
||||
assertEquals(-.25, createGrade(5, 0, -.33).changeModifier(.0, .25).modifier, .0)
|
||||
assertEquals(-.33, createGrade(5, .0, -.25).changeModifier(.25, .33).modifier, .0)
|
||||
assertEquals(-.25, createGrade(5, .0, -.33).changeModifier(.0, .25).modifier, .0)
|
||||
}
|
||||
|
||||
private fun createGrade(value: Int, weightValue: Int = 0, modifier: Double = 0.25): Grade {
|
||||
private fun createGrade(value: Int, weightValue: Double = .0, modifier: Double = 0.25): Grade {
|
||||
return Grade(
|
||||
semesterId = 1,
|
||||
studentId = 1,
|
||||
|
Reference in New Issue
Block a user