Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
153e026a8d | |||
8731c2e1f2 | |||
0977282a4b | |||
667c4b6af7 | |||
1f5088cfc9 | |||
bf6b857a3e | |||
80cb94c434 | |||
0cb4eda32b | |||
d169f964f2 | |||
103ab95c80 | |||
a191f03cdf | |||
63404b8576 | |||
1b7760ff88 | |||
24f58835e7 | |||
b032c459d1 | |||
df0a1e59cc | |||
dbbc8069b1 | |||
f84040109c | |||
baf1420193 | |||
4a36d78709 | |||
4464812651 | |||
72a35481e5 | |||
017c200115 | |||
2bf7755157 | |||
269af4b7ba | |||
7431738366 | |||
034b99c7ab | |||
74e98e4430 | |||
cbf3215dd1 | |||
c18877466f | |||
6cd6cae1e0 | |||
333f7bfa16 | |||
aa6dcaff94 | |||
f2fa04105d | |||
7d97d71066 | |||
8daea5c900 | |||
2bff468e56 | |||
f2855d598d | |||
297a2909ba | |||
935bec3f5b | |||
e71dd55066 | |||
4e3864f26f | |||
8601093725 | |||
b97b94ae29 | |||
c6c7357623 | |||
1ebc296bfe | |||
c2ab53cfeb | |||
87268b3ef6 | |||
b3cd7e8ac1 | |||
a2a18e5652 | |||
cd1ceea860 |
@ -7,11 +7,11 @@ references:
|
|||||||
|
|
||||||
container_config: &container_config
|
container_config: &container_config
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/android:api-28-alpha
|
- image: circleci/android:api-28
|
||||||
working_directory: *workspace_root
|
working_directory: *workspace_root
|
||||||
environment:
|
environment:
|
||||||
environment:
|
environment:
|
||||||
JVM_OPTS: -Xmx3200m
|
_JAVA_OPTS: -Xmx3072m
|
||||||
|
|
||||||
attach_workspace: &attach_workspace
|
attach_workspace: &attach_workspace
|
||||||
attach_workspace:
|
attach_workspace:
|
||||||
|
25
.idea/codeStyles/Project.xml
generated
25
.idea/codeStyles/Project.xml
generated
@ -21,31 +21,6 @@
|
|||||||
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
|
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
|
||||||
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
|
||||||
</JetCodeStyleSettings>
|
</JetCodeStyleSettings>
|
||||||
<Objective-C-extensions>
|
|
||||||
<file>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
|
||||||
</file>
|
|
||||||
<class>
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
|
||||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
|
||||||
</class>
|
|
||||||
<extensions>
|
|
||||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
|
||||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
|
||||||
</extensions>
|
|
||||||
</Objective-C-extensions>
|
|
||||||
<XML>
|
<XML>
|
||||||
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
<option name="XML_KEEP_LINE_BREAKS" value="false" />
|
||||||
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
|
||||||
|
@ -13,8 +13,8 @@ cache:
|
|||||||
|
|
||||||
#branches:
|
#branches:
|
||||||
# only:
|
# only:
|
||||||
# - master
|
# - master
|
||||||
# - 0.7.x
|
# - 0.8.x
|
||||||
|
|
||||||
android:
|
android:
|
||||||
licenses:
|
licenses:
|
||||||
|
@ -16,15 +16,24 @@ android {
|
|||||||
testApplicationId "io.github.tests.wulkanowy"
|
testApplicationId "io.github.tests.wulkanowy"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 28
|
versionCode 36
|
||||||
versionName "0.7.2"
|
versionName "0.8.3"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
fabric_api_key: System.getenv("FABRIC_API_KEY") ?: "null",
|
fabric_api_key : System.getenv("FABRIC_API_KEY") ?: "null",
|
||||||
crashlytics_enabled: project.hasProperty("enableCrashlytics")
|
crashlytics_enabled: project.hasProperty("enableCrashlytics")
|
||||||
]
|
]
|
||||||
|
javaCompileOptions {
|
||||||
|
annotationProcessorOptions {
|
||||||
|
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@ -71,53 +80,54 @@ androidExtensions {
|
|||||||
play {
|
play {
|
||||||
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
|
||||||
serviceAccountCredentials = file('key.p12')
|
serviceAccountCredentials = file('key.p12')
|
||||||
defaultToAppBundles = true
|
defaultToAppBundles = false
|
||||||
track = 'alpha'
|
track = 'alpha'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
implementation 'io.github.wulkanowy:api:0.8.3'
|
||||||
implementation('io.github.wulkanowy:api:0.7.2') { exclude module: "threetenbp" }
|
|
||||||
|
|
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.0.2"
|
implementation "androidx.appcompat:appcompat:1.0.2"
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
|
||||||
implementation "com.google.android.material:material:1.0.0"
|
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime:2.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation "androidx.work:work-rxjava2:2.0.0"
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
implementation "com.google.android.material:material:1.1.0-alpha05"
|
||||||
|
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
|
||||||
|
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
||||||
|
|
||||||
implementation "androidx.room:room-runtime:2.1.0-alpha06"
|
implementation "androidx.work:work-runtime:2.0.1"
|
||||||
implementation "androidx.room:room-rxjava2:2.1.0-alpha06"
|
implementation "androidx.work:work-rxjava2:2.0.1"
|
||||||
kapt "androidx.room:room-compiler:2.1.0-alpha06"
|
|
||||||
|
|
||||||
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
implementation "androidx.room:room-runtime:2.1.0-alpha07"
|
||||||
|
implementation "androidx.room:room-rxjava2:2.1.0-alpha07"
|
||||||
|
kapt "androidx.room:room-compiler:2.1.0-alpha07"
|
||||||
|
|
||||||
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.3.3'
|
implementation "com.google.dagger:dagger-android-support:2.22.1"
|
||||||
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.3.3'
|
kapt "com.google.dagger:dagger-compiler:2.22.1"
|
||||||
|
kapt "com.google.dagger:dagger-android-processor:2.22.1"
|
||||||
implementation "com.google.dagger:dagger-android-support:2.21"
|
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
|
||||||
kapt "com.google.dagger:dagger-compiler:2.21"
|
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
|
||||||
kapt "com.google.dagger:dagger-android-processor:2.21"
|
|
||||||
|
|
||||||
implementation "eu.davidea:flexible-adapter:5.1.0"
|
implementation "eu.davidea:flexible-adapter:5.1.0"
|
||||||
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
|
||||||
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
|
||||||
implementation 'com.ncapdevi:frag-nav:3.2.0'
|
implementation 'com.ncapdevi:frag-nav:3.2.0'
|
||||||
|
|
||||||
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
|
|
||||||
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
|
|
||||||
|
|
||||||
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2'
|
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.2'
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
implementation "io.reactivex.rxjava2:rxjava:2.2.7"
|
implementation "io.reactivex.rxjava2:rxjava:2.2.8"
|
||||||
|
|
||||||
|
implementation 'com.google.code.gson:gson:2.8.5'
|
||||||
implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
|
implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
|
||||||
implementation "com.jakewharton.timber:timber:4.7.1"
|
implementation "com.jakewharton.timber:timber:4.7.1"
|
||||||
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
implementation "at.favre.lib:slf4j-timber:1.0.1"
|
||||||
|
implementation "com.squareup.okhttp3:logging-interceptor:3.12.1"
|
||||||
|
|
||||||
implementation "com.mikepenz:aboutlibraries:6.2.3"
|
implementation "com.mikepenz:aboutlibraries:6.2.3"
|
||||||
|
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
|
||||||
|
|
||||||
implementation 'com.google.firebase:firebase-core:16.0.8'
|
implementation 'com.google.firebase:firebase-core:16.0.8'
|
||||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
|
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
|
||||||
@ -129,14 +139,15 @@ dependencies {
|
|||||||
|
|
||||||
testImplementation "junit:junit:4.12"
|
testImplementation "junit:junit:4.12"
|
||||||
testImplementation "io.mockk:mockk:1.9.2"
|
testImplementation "io.mockk:mockk:1.9.2"
|
||||||
testImplementation "org.mockito:mockito-inline:2.25.1"
|
testImplementation "org.mockito:mockito-inline:2.27.0"
|
||||||
testImplementation 'org.threeten:threetenbp:1.3.8'
|
testImplementation 'org.threeten:threetenbp:1.3.8'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.1.0'
|
androidTestImplementation 'androidx.test:core:1.1.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.1.1'
|
androidTestImplementation 'androidx.test:runner:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
|
||||||
androidTestImplementation "io.mockk:mockk-android:1.9.2"
|
androidTestImplementation "io.mockk:mockk-android:1.9.2"
|
||||||
androidTestImplementation 'org.mockito:mockito-android:2.25.1'
|
androidTestImplementation 'org.mockito:mockito-android:2.27.0'
|
||||||
|
androidTestImplementation "androidx.room:room-testing:2.1.0-alpha07"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,17 +31,17 @@ task jacocoTestReport(type: JacocoReport) {
|
|||||||
'**/*_Provide*Factory*.*',
|
'**/*_Provide*Factory*.*',
|
||||||
'**/*_Factory.*']
|
'**/*_Factory.*']
|
||||||
|
|
||||||
classDirectories = fileTree(
|
classDirectories.setFrom(fileTree(
|
||||||
dir: "$buildDir/intermediates/classes/debug",
|
dir: "$buildDir/intermediates/classes/debug",
|
||||||
excludes: excludes
|
excludes: excludes
|
||||||
) + fileTree(
|
) + fileTree(
|
||||||
dir: "$buildDir/tmp/kotlin-classes/debug",
|
dir: "$buildDir/tmp/kotlin-classes/debug",
|
||||||
excludes: excludes
|
excludes: excludes
|
||||||
)
|
))
|
||||||
|
|
||||||
sourceDirectories = files("$project.projectDir/src/main/java")
|
sourceDirectories.setFrom(files("$project.projectDir/src/main/java"))
|
||||||
executionData = fileTree(
|
executionData.setFrom(fileTree(
|
||||||
dir: project.projectDir,
|
dir: project.projectDir,
|
||||||
includes: ["**/*.exec", "**/*.ec"]
|
includes: ["**/*.exec", "**/*.ec"]
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
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.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
|
import org.threeten.bp.LocalDate.now
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@ -40,7 +41,7 @@ class AttendanceLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val attendance = attendanceLocal
|
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, 10),
|
||||||
LocalDate.of(2018, 9, 14)
|
LocalDate.of(2018, 9, 14)
|
||||||
)
|
)
|
||||||
|
@ -41,7 +41,7 @@ class CompletedLessonsLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val completed = completedLessonsLocal
|
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, 10),
|
||||||
LocalDate.of(2018, 9, 14)
|
LocalDate.of(2018, 9, 14)
|
||||||
)
|
)
|
||||||
|
@ -40,7 +40,7 @@ class ExamLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val exams = examLocal
|
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, 10),
|
||||||
LocalDate.of(2018, 9, 14)
|
LocalDate.of(2018, 9, 14)
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
|
import org.threeten.bp.LocalDate.now
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@ -39,8 +40,10 @@ class GradeLocalTest {
|
|||||||
createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 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
|
val grades = gradeLocal
|
||||||
.getGrades(Semester(1, 2, "", 2, 3, true, 1, 1))
|
.getGrades(semester)
|
||||||
.blockingGet()
|
.blockingGet()
|
||||||
|
|
||||||
assertEquals(2, grades.size)
|
assertEquals(2, grades.size)
|
||||||
|
@ -22,6 +22,7 @@ import org.junit.Test
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.threeten.bp.LocalDate.of
|
import org.threeten.bp.LocalDate.of
|
||||||
import org.threeten.bp.LocalDateTime
|
import org.threeten.bp.LocalDateTime
|
||||||
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
import io.github.wulkanowy.api.grades.Grade as GradeApi
|
import io.github.wulkanowy.api.grades.Grade as GradeApi
|
||||||
@ -109,4 +110,73 @@ class GradeRepositoryTest {
|
|||||||
assertTrue { grades[2].isRead }
|
assertTrue { grades[2].isRead }
|
||||||
assertTrue { grades[3].isRead }
|
assertTrue { grades[3].isRead }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun subtractLocaleDuplicateGrades() {
|
||||||
|
gradeLocal.saveGrades(listOf(
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(2, grades.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun subtractRemoteDuplicateGrades() {
|
||||||
|
gradeLocal.saveGrades(listOf(
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(3, grades.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun emptyLocal() {
|
||||||
|
gradeLocal.saveGrades(listOf())
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf(
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(3, grades.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun emptyRemote() {
|
||||||
|
gradeLocal.saveGrades(listOf(
|
||||||
|
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
|
||||||
|
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
|
||||||
|
))
|
||||||
|
|
||||||
|
every { mockApi.getGrades(1) } returns Single.just(listOf())
|
||||||
|
|
||||||
|
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
|
||||||
|
.getGrades(studentMock, semesterMock, true).blockingGet()
|
||||||
|
|
||||||
|
assertEquals(0, grades.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import org.junit.After
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
@ -39,7 +40,7 @@ class GradeStatisticsLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val stats = gradeStatisticsLocal.getGradesStatistics(
|
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"
|
"Matematyka"
|
||||||
).blockingGet()
|
).blockingGet()
|
||||||
assertEquals(1, stats.size)
|
assertEquals(1, stats.size)
|
||||||
@ -55,7 +56,7 @@ class GradeStatisticsLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val stats = gradeStatisticsLocal.getGradesStatistics(
|
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"
|
"Wszystkie"
|
||||||
).blockingGet()
|
).blockingGet()
|
||||||
assertEquals(1, stats.size)
|
assertEquals(1, stats.size)
|
||||||
|
@ -36,7 +36,7 @@ class LuckyNumberLocalTest {
|
|||||||
fun saveAndReadTest() {
|
fun saveAndReadTest() {
|
||||||
luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
|
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)
|
LocalDate.of(2019, 1, 20)
|
||||||
).blockingGet()
|
).blockingGet()
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class RecipientLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val recipients = recipientLocal.getRecipients(
|
val recipients = recipientLocal.getRecipients(
|
||||||
Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", true, LocalDateTime.now()),
|
Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", "", 1, true, LocalDateTime.now()),
|
||||||
2,
|
2,
|
||||||
ReportingUnit(1, 4, "", 0, "", emptyList())
|
ReportingUnit(1, 4, "", 0, "", emptyList())
|
||||||
).blockingGet()
|
).blockingGet()
|
||||||
|
@ -39,7 +39,7 @@ class StudentLocalTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun saveAndReadTest() {
|
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.saveStudents(listOf(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()
|
.blockingGet()
|
||||||
|
|
||||||
val student = studentLocal.getCurrentStudent(true).blockingGet()
|
val student = studentLocal.getCurrentStudent(true).blockingGet()
|
||||||
|
@ -7,7 +7,7 @@ import org.threeten.bp.LocalDateTime.now
|
|||||||
import io.github.wulkanowy.api.timetable.Timetable as TimetableRemote
|
import io.github.wulkanowy.api.timetable.Timetable as TimetableRemote
|
||||||
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
|
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
|
||||||
|
|
||||||
fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", subject: String = ""): TimetableLocal {
|
fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", subject: String = "", teacher: String = ""): TimetableLocal {
|
||||||
return TimetableLocal(
|
return TimetableLocal(
|
||||||
studentId = 1,
|
studentId = 1,
|
||||||
diaryId = 2,
|
diaryId = 2,
|
||||||
@ -20,7 +20,7 @@ fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", s
|
|||||||
group = "",
|
group = "",
|
||||||
room = room,
|
room = room,
|
||||||
roomOld = "",
|
roomOld = "",
|
||||||
teacher = "",
|
teacher = teacher,
|
||||||
teacherOld = "",
|
teacherOld = "",
|
||||||
info = "",
|
info = "",
|
||||||
changes = false,
|
changes = false,
|
||||||
@ -28,7 +28,7 @@ fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", s
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTimetableRemote(number: Int, start: LocalDateTime, room: String, subject: String = ""): TimetableRemote {
|
fun createTimetableRemote(number: Int, start: LocalDateTime, room: String, subject: String = "", teacher: String = ""): TimetableRemote {
|
||||||
return TimetableRemote(
|
return TimetableRemote(
|
||||||
number = number,
|
number = number,
|
||||||
start = start.toDate(),
|
start = start.toDate(),
|
||||||
@ -37,7 +37,7 @@ fun createTimetableRemote(number: Int, start: LocalDateTime, room: String, subje
|
|||||||
subject = subject,
|
subject = subject,
|
||||||
group = "",
|
group = "",
|
||||||
room = room,
|
room = room,
|
||||||
teacher = "",
|
teacher = teacher,
|
||||||
info = "",
|
info = "",
|
||||||
changes = false,
|
changes = false,
|
||||||
canceled = false
|
canceled = false
|
||||||
|
@ -41,7 +41,7 @@ class TimetableLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val exams = timetableDb.getTimetable(
|
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, 10),
|
||||||
LocalDate.of(2018, 9, 14)
|
LocalDate.of(2018, 9, 14)
|
||||||
).blockingGet()
|
).blockingGet()
|
||||||
|
@ -63,23 +63,27 @@ class TimetableRepositoryTest {
|
|||||||
fun copyDetailsToCompletedFromPrevious() {
|
fun copyDetailsToCompletedFromPrevious() {
|
||||||
timetableLocal.saveTimetable(listOf(
|
timetableLocal.saveTimetable(listOf(
|
||||||
createTimetableLocal(1, of(2019, 3, 5, 8, 0), "123", "Przyroda"),
|
createTimetableLocal(1, of(2019, 3, 5, 8, 0), "123", "Przyroda"),
|
||||||
createTimetableLocal(1, of(2019, 3, 5, 8, 50), "321", "Religia"),
|
createTimetableLocal(2, of(2019, 3, 5, 8, 50), "321", "Religia"),
|
||||||
createTimetableLocal(1, of(2019, 3, 5, 9, 40), "213", "W-F")
|
createTimetableLocal(3, of(2019, 3, 5, 9, 40), "213", "W-F"),
|
||||||
|
createTimetableLocal(4, of(2019, 3, 5, 10, 30), "213", "W-F", "Jan Kowalski")
|
||||||
))
|
))
|
||||||
|
|
||||||
every { mockApi.getTimetable(any(), any()) } returns Single.just(listOf(
|
every { mockApi.getTimetable(any(), any()) } returns Single.just(listOf(
|
||||||
createTimetableRemote(1, of(2019, 3, 5, 8, 0), "", "Przyroda"),
|
createTimetableRemote(1, of(2019, 3, 5, 8, 0), "", "Przyroda"),
|
||||||
createTimetableRemote(1, of(2019, 3, 5, 8, 50), "", "Religia"),
|
createTimetableRemote(2, of(2019, 3, 5, 8, 50), "", "Religia"),
|
||||||
createTimetableRemote(1, of(2019, 3, 5, 9, 40), "", "W-F")
|
createTimetableRemote(3, of(2019, 3, 5, 9, 40), "", "W-F"),
|
||||||
|
createTimetableRemote(4, of(2019, 3, 5, 10, 30), "", "W-F")
|
||||||
))
|
))
|
||||||
|
|
||||||
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
|
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
|
||||||
.getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
|
.getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
|
||||||
.blockingGet()
|
.blockingGet()
|
||||||
|
|
||||||
assertEquals(3, lessons.size)
|
assertEquals(4, lessons.size)
|
||||||
assertEquals("123", lessons[0].room)
|
assertEquals("123", lessons[0].room)
|
||||||
assertEquals("321", lessons[1].room)
|
assertEquals("321", lessons[1].room)
|
||||||
assertEquals("213", lessons[2].room)
|
assertEquals("213", lessons[2].room)
|
||||||
|
|
||||||
|
assertEquals("", lessons[3].teacher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
android:name=".ui.modules.login.LoginActivity"
|
android:name=".ui.modules.login.LoginActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/login_title"
|
android:label="@string/login_title"
|
||||||
|
android:theme="@style/WulkanowyTheme.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize" />
|
android:windowSoftInputMode="adjustResize" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.modules.main.MainActivity"
|
android:name=".ui.modules.main.MainActivity"
|
||||||
@ -45,13 +46,31 @@
|
|||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/send_message_title"
|
android:label="@string/send_message_title"
|
||||||
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
android:theme="@style/WulkanowyTheme.NoActionBar" />
|
||||||
|
<activity
|
||||||
|
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".services.widgets.TimetableWidgetService"
|
android:name=".services.widgets.TimetableWidgetService"
|
||||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".ui.widgets.timetable.TimetableWidgetProvider"
|
android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/timetable_title">
|
android:label="@string/timetable_title">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@ -62,6 +81,17 @@
|
|||||||
android:resource="@xml/provider_widget_timetable" />
|
android:resource="@xml/provider_widget_timetable" />
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
|
||||||
|
android:label="@string/lucky_number_title">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/provider_widget_lucky_number" />
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||||
android:authorities="${applicationId}.workmanager-init"
|
android:authorities="${applicationId}.workmanager-init"
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package io.github.wulkanowy
|
package io.github.wulkanowy
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.multidex.MultiDex
|
import androidx.multidex.MultiDex
|
||||||
import androidx.work.Configuration
|
import androidx.work.Configuration
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
@ -13,20 +12,21 @@ import dagger.android.support.DaggerApplication
|
|||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.utils.Log
|
import eu.davidea.flexibleadapter.utils.Log
|
||||||
import io.fabric.sdk.android.Fabric
|
import io.fabric.sdk.android.Fabric
|
||||||
|
import io.github.wulkanowy.BuildConfig.CRASHLYTICS_ENABLED
|
||||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.di.DaggerAppComponent
|
import io.github.wulkanowy.di.DaggerAppComponent
|
||||||
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
import io.github.wulkanowy.services.sync.SyncWorkerFactory
|
||||||
|
import io.github.wulkanowy.utils.ActivityLifecycleLogger
|
||||||
import io.github.wulkanowy.utils.CrashlyticsTree
|
import io.github.wulkanowy.utils.CrashlyticsTree
|
||||||
import io.github.wulkanowy.utils.DebugLogTree
|
import io.github.wulkanowy.utils.DebugLogTree
|
||||||
|
import io.reactivex.exceptions.UndeliverableException
|
||||||
|
import io.reactivex.plugins.RxJavaPlugins
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.io.IOException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class WulkanowyApp : DaggerApplication() {
|
class WulkanowyApp : DaggerApplication() {
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var prefRepository: PreferencesRepository
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var workerFactory: SyncWorkerFactory
|
lateinit var workerFactory: SyncWorkerFactory
|
||||||
|
|
||||||
@ -38,25 +38,36 @@ class WulkanowyApp : DaggerApplication() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
AndroidThreeTen.init(this)
|
AndroidThreeTen.init(this)
|
||||||
initializeFabric()
|
|
||||||
if (DEBUG) enableDebugLog()
|
|
||||||
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
|
|
||||||
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
|
||||||
|
RxJavaPlugins.setErrorHandler(::onError)
|
||||||
|
|
||||||
|
initCrashlytics()
|
||||||
|
initLogging()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableDebugLog() {
|
private fun initLogging() {
|
||||||
Timber.plant(DebugLogTree())
|
if (DEBUG) {
|
||||||
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
|
Timber.plant(DebugLogTree())
|
||||||
|
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
|
||||||
|
} else {
|
||||||
|
Timber.plant(CrashlyticsTree())
|
||||||
|
}
|
||||||
|
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeFabric() {
|
private fun initCrashlytics() {
|
||||||
Fabric.with(Fabric.Builder(this).kits(
|
Fabric.with(Fabric.Builder(this).kits(
|
||||||
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!BuildConfig.CRASHLYTICS_ENABLED).build()).build()
|
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!CRASHLYTICS_ENABLED).build()).build()
|
||||||
).debuggable(BuildConfig.DEBUG).build())
|
).debuggable(DEBUG).build())
|
||||||
Timber.plant(CrashlyticsTree())
|
}
|
||||||
|
|
||||||
|
private fun onError(error: Throwable) {
|
||||||
|
if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) {
|
||||||
|
Timber.e(error.cause, "An undeliverable error occurred")
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
|
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
|
||||||
return DaggerAppComponent.builder().create(this)
|
return DaggerAppComponent.factory().create(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ class ApiHelper @Inject constructor(private val api: Api) {
|
|||||||
symbol = student.symbol
|
symbol = student.symbol
|
||||||
schoolSymbol = student.schoolSymbol
|
schoolSymbol = student.schoolSymbol
|
||||||
studentId = student.studentId
|
studentId = student.studentId
|
||||||
|
classId = student.classId
|
||||||
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
|
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
|
||||||
ssl = student.endpoint.startsWith("https")
|
ssl = student.endpoint.startsWith("https")
|
||||||
loginType = Api.LoginType.valueOf(student.loginType)
|
loginType = Api.LoginType.valueOf(student.loginType)
|
||||||
@ -28,6 +29,7 @@ class ApiHelper @Inject constructor(private val api: Api) {
|
|||||||
this.symbol = symbol
|
this.symbol = symbol
|
||||||
host = URL(endpoint).run { host + ":$port".removeSuffix(":-1") }
|
host = URL(endpoint).run { host + ":$port".removeSuffix(":-1") }
|
||||||
ssl = endpoint.startsWith("https")
|
ssl = endpoint.startsWith("https")
|
||||||
|
useNewStudent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ import io.github.wulkanowy.data.db.entities.Subject
|
|||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration10
|
import io.github.wulkanowy.data.db.migrations.Migration10
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration11
|
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.Migration2
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration3
|
import io.github.wulkanowy.data.db.migrations.Migration3
|
||||||
import io.github.wulkanowy.data.db.migrations.Migration4
|
import io.github.wulkanowy.data.db.migrations.Migration4
|
||||||
@ -74,13 +76,13 @@ import javax.inject.Singleton
|
|||||||
Recipient::class
|
Recipient::class
|
||||||
],
|
],
|
||||||
version = AppDatabase.VERSION_SCHEMA,
|
version = AppDatabase.VERSION_SCHEMA,
|
||||||
exportSchema = false
|
exportSchema = true
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val VERSION_SCHEMA = 11
|
const val VERSION_SCHEMA = 13
|
||||||
|
|
||||||
fun newInstance(context: Context): AppDatabase {
|
fun newInstance(context: Context): AppDatabase {
|
||||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||||
@ -97,7 +99,9 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
Migration8(),
|
Migration8(),
|
||||||
Migration9(),
|
Migration9(),
|
||||||
Migration10(),
|
Migration10(),
|
||||||
Migration11()
|
Migration11(),
|
||||||
|
Migration12(),
|
||||||
|
Migration13()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
@ -6,18 +6,16 @@ import javax.inject.Inject
|
|||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@SuppressLint("ApplySharedPref")
|
||||||
class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPreferences) {
|
class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPreferences) {
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
|
||||||
fun putLong(key: String, value: Long, sync: Boolean = false) {
|
fun putLong(key: String, value: Long, sync: Boolean = false) {
|
||||||
sharedPref.edit().putLong(key, value).apply {
|
sharedPref.edit().putLong(key, value).apply {
|
||||||
if (sync) commit() else apply()
|
if (sync) commit() else apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLong(key: String, defaultValue: Long): Long {
|
fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
|
||||||
return sharedPref.getLong(key, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun delete(key: String) {
|
fun delete(key: String) {
|
||||||
sharedPref.edit().remove(key).apply()
|
sharedPref.edit().remove(key).apply()
|
||||||
|
@ -23,8 +23,8 @@ interface MessagesDao {
|
|||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
|
||||||
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
|
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND real_id = :id")
|
@Query("SELECT * FROM Messages WHERE id = :id")
|
||||||
fun load(studentId: Int, id: Int): Maybe<Message>
|
fun load(id: Long): Maybe<Message>
|
||||||
|
|
||||||
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
|
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
|
||||||
fun loadDeleted(studentId: Int): Maybe<List<Message>>
|
fun loadDeleted(studentId: Int): Maybe<List<Message>>
|
||||||
|
@ -18,6 +18,6 @@ interface SemesterDao {
|
|||||||
@Delete
|
@Delete
|
||||||
fun deleteAll(semester: List<Semester>)
|
fun deleteAll(semester: List<Semester>)
|
||||||
|
|
||||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
@Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
|
||||||
fun loadAll(studentId: Int): Maybe<List<Semester>>
|
fun loadAll(studentId: Int, classId: Int): Maybe<List<Semester>>
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import javax.inject.Singleton
|
|||||||
interface StudentDao {
|
interface StudentDao {
|
||||||
|
|
||||||
@Insert(onConflict = ABORT)
|
@Insert(onConflict = ABORT)
|
||||||
fun insert(student: Student): Long
|
fun insertAll(student: List<Student>): List<Long>
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
fun delete(student: Student)
|
fun delete(student: Student)
|
||||||
@ -25,8 +25,8 @@ interface StudentDao {
|
|||||||
@Query("SELECT * FROM Students")
|
@Query("SELECT * FROM Students")
|
||||||
fun loadAll(): Maybe<List<Student>>
|
fun loadAll(): Maybe<List<Student>>
|
||||||
|
|
||||||
@Query("UPDATE Students SET is_current = 1 WHERE student_id = :studentId")
|
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||||
fun updateCurrent(studentId: Int)
|
fun updateCurrent(id: Long)
|
||||||
|
|
||||||
@Query("UPDATE Students SET is_current = 0")
|
@Query("UPDATE Students SET is_current = 0")
|
||||||
fun resetCurrent()
|
fun resetCurrent()
|
||||||
|
@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
|
|||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.Index
|
import androidx.room.Index
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import org.threeten.bp.LocalDate
|
||||||
|
|
||||||
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
|
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
|
||||||
data class Semester(
|
data class Semester(
|
||||||
@ -17,6 +18,9 @@ data class Semester(
|
|||||||
@ColumnInfo(name = "diary_name")
|
@ColumnInfo(name = "diary_name")
|
||||||
val diaryName: String,
|
val diaryName: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "school_year")
|
||||||
|
val schoolYear: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "semester_id")
|
@ColumnInfo(name = "semester_id")
|
||||||
val semesterId: Int,
|
val semesterId: Int,
|
||||||
|
|
||||||
@ -26,6 +30,10 @@ data class Semester(
|
|||||||
@ColumnInfo(name = "is_current")
|
@ColumnInfo(name = "is_current")
|
||||||
val isCurrent: Boolean,
|
val isCurrent: Boolean,
|
||||||
|
|
||||||
|
val start: LocalDate,
|
||||||
|
|
||||||
|
val end: LocalDate,
|
||||||
|
|
||||||
@ColumnInfo(name = "class_id")
|
@ColumnInfo(name = "class_id")
|
||||||
val classId: Int,
|
val classId: Int,
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import androidx.room.PrimaryKey
|
|||||||
import org.threeten.bp.LocalDateTime
|
import org.threeten.bp.LocalDateTime
|
||||||
import java.io.Serializable
|
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(
|
data class Student(
|
||||||
|
|
||||||
val endpoint: String,
|
val endpoint: String,
|
||||||
@ -32,6 +32,12 @@ data class Student(
|
|||||||
@ColumnInfo(name = "school_name")
|
@ColumnInfo(name = "school_name")
|
||||||
val schoolName: String,
|
val schoolName: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "class_name")
|
||||||
|
val className: String,
|
||||||
|
|
||||||
|
@ColumnInfo(name = "class_id")
|
||||||
|
val classId: Int,
|
||||||
|
|
||||||
@ColumnInfo(name = "is_current")
|
@ColumnInfo(name = "is_current")
|
||||||
val isCurrent: Boolean,
|
val isCurrent: Boolean,
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ class Migration11 : Migration(10, 11) {
|
|||||||
override fun migrate(database: SupportSQLiteDatabase) {
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
database.execSQL("""
|
database.execSQL("""
|
||||||
CREATE TABLE IF NOT EXISTS Grades_temp (
|
CREATE TABLE IF NOT EXISTS Grades_temp (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
is_read INTEGER NOT NULL,
|
is_read INTEGER NOT NULL,
|
||||||
is_notified INTEGER NOT NULL,
|
is_notified INTEGER NOT NULL,
|
||||||
semester_id INTEGER NOT NULL,
|
semester_id INTEGER NOT NULL,
|
||||||
|
@ -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")
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Attendance
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -31,8 +32,8 @@ class AttendanceRepository @Inject constructor(
|
|||||||
local.getAttendance(semester, dates.first, dates.second)
|
local.getAttendance(semester, dates.first, dates.second)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { oldAttendance ->
|
.doOnSuccess { oldAttendance ->
|
||||||
local.deleteAttendance(oldAttendance - newAttendance)
|
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
|
||||||
local.saveAttendance(newAttendance - oldAttendance)
|
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getAttendance(semester, dates.first, dates.second)
|
local.getAttendance(semester, dates.first, dates.second)
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
import io.github.wulkanowy.data.db.entities.AttendanceSummary
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -25,8 +26,8 @@ class AttendanceSummaryRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
|
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteAttendanceSummary(old - new)
|
local.deleteAttendanceSummary(old.uniqueSubtract(new))
|
||||||
local.saveAttendanceSummary(new - old)
|
local.saveAttendanceSummary(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) })
|
}.flatMap { local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.CompletedLesson
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -31,8 +32,8 @@ class CompletedLessonsRepository @Inject constructor(
|
|||||||
local.getCompletedLessons(semester, dates.first, dates.second)
|
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteCompleteLessons(old - new)
|
local.deleteCompleteLessons(old.uniqueSubtract(new))
|
||||||
local.saveCompletedLessons(new - old)
|
local.saveCompletedLessons(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getCompletedLessons(semester, dates.first, dates.second)
|
local.getCompletedLessons(semester, dates.first, dates.second)
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Exam
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -27,12 +28,12 @@ class ExamRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getExams(semester, dates.first, dates.second)
|
if (it) remote.getExams(semester, dates.first, dates.second)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newExams ->
|
}.flatMap { new ->
|
||||||
local.getExams(semester, dates.first, dates.second)
|
local.getExams(semester, dates.first, dates.second)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { oldExams ->
|
.doOnSuccess { old ->
|
||||||
local.deleteExams(oldExams - newExams)
|
local.deleteExams(old.uniqueSubtract(new))
|
||||||
local.saveExams(newExams - oldExams)
|
local.saveExams(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getExams(semester, dates.first, dates.second)
|
local.getExams(semester, dates.first, dates.second)
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.db.entities.Grade
|
import io.github.wulkanowy.data.db.entities.Grade
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -24,13 +25,12 @@ class GradeRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGrades(semester)
|
if (it) remote.getGrades(semester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGrades ->
|
}.flatMap { new ->
|
||||||
local.getGrades(semester).toSingle(emptyList())
|
local.getGrades(semester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGrades ->
|
.doOnSuccess { old ->
|
||||||
val notifyBreakDate = oldGrades.maxBy { it.date }?.date
|
val notifyBreakDate = old.maxBy { it.date }?.date ?: student.registrationDate.toLocalDate()
|
||||||
?: student.registrationDate.toLocalDate()
|
local.deleteGrades(old.uniqueSubtract(new))
|
||||||
local.deleteGrades(oldGrades - newGrades)
|
local.saveGrades(new.uniqueSubtract(old)
|
||||||
local.saveGrades((newGrades - oldGrades)
|
|
||||||
.onEach {
|
.onEach {
|
||||||
if (it.date >= notifyBreakDate) it.apply {
|
if (it.date >= notifyBreakDate) it.apply {
|
||||||
isRead = false
|
isRead = false
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -22,11 +23,11 @@ class GradeSummaryRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGradeSummary(semester)
|
if (it) remote.getGradeSummary(semester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGradesSummary ->
|
}.flatMap { new ->
|
||||||
local.getGradesSummary(semester).toSingle(emptyList())
|
local.getGradesSummary(semester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGradesSummary ->
|
.doOnSuccess { old ->
|
||||||
local.deleteGradesSummary(oldGradesSummary - newGradesSummary)
|
local.deleteGradesSummary(old.uniqueSubtract(new))
|
||||||
local.saveGradesSummary(newGradesSummary - oldGradesSummary)
|
local.saveGradesSummary(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) })
|
}.flatMap { local.getGradesSummary(semester).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -22,11 +23,11 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGradeStatistics(semester, isSemester)
|
if (it) remote.getGradeStatistics(semester, isSemester)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGradesStats ->
|
}.flatMap { new ->
|
||||||
local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
|
local.getGradesStatistics(semester, isSemester).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGradesStats ->
|
.doOnSuccess { old ->
|
||||||
local.deleteGradesStatistics(oldGradesStats - newGradesStats)
|
local.deleteGradesStatistics(old.uniqueSubtract(new))
|
||||||
local.saveGradesStatistics(newGradesStats - oldGradesStats)
|
local.saveGradesStatistics(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
|
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Homework
|
|||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -26,11 +27,11 @@ class HomeworkRepository @Inject constructor(
|
|||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getHomework(semester, monday, friday)
|
if (it) remote.getHomework(semester, monday, friday)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newGrades ->
|
}.flatMap { new ->
|
||||||
local.getHomework(semester, monday, friday).toSingle(emptyList())
|
local.getHomework(semester, monday, friday).toSingle(emptyList())
|
||||||
.doOnSuccess { oldGrades ->
|
.doOnSuccess { old ->
|
||||||
local.deleteHomework(oldGrades - newGrades)
|
local.deleteHomework(old.uniqueSubtract(new))
|
||||||
local.saveHomework(newGrades - oldGrades)
|
local.saveHomework(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
}.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
@ -23,14 +23,14 @@ class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) {
|
|||||||
messagesDb.deleteAll(messages)
|
messagesDb.deleteAll(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessage(student: Student, id: Int): Maybe<Message> {
|
fun getMessage(id: Long): Maybe<Message> {
|
||||||
return messagesDb.load(student.studentId, id)
|
return messagesDb.load(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
|
fun getMessages(student: Student, folder: MessageFolder): Maybe<List<Message>> {
|
||||||
return when (folder) {
|
return when (folder) {
|
||||||
TRASHED -> messagesDb.loadDeleted(student.studentId)
|
TRASHED -> messagesDb.loadDeleted(student.id.toInt())
|
||||||
else -> messagesDb.loadAll(student.studentId, folder.id)
|
else -> messagesDb.loadAll(student.id.toInt(), folder.id)
|
||||||
}.filter { it.isNotEmpty() }
|
}.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.api.messages.SentMessage
|
||||||
import io.github.wulkanowy.data.db.entities.Message
|
import io.github.wulkanowy.data.db.entities.Message
|
||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.utils.toLocalDateTime
|
import io.github.wulkanowy.utils.toLocalDateTime
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDateTime.now
|
import org.threeten.bp.LocalDateTime.now
|
||||||
@ -16,11 +17,11 @@ import io.github.wulkanowy.api.messages.Recipient as ApiRecipient
|
|||||||
@Singleton
|
@Singleton
|
||||||
class MessageRemote @Inject constructor(private val api: Api) {
|
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 ->
|
return api.getMessages(Folder.valueOf(folder.name)).map { messages ->
|
||||||
messages.map {
|
messages.map {
|
||||||
Message(
|
Message(
|
||||||
studentId = studentId,
|
studentId = student.id.toInt(),
|
||||||
realId = it.id ?: 0,
|
realId = it.id ?: 0,
|
||||||
messageId = it.messageId ?: 0,
|
messageId = it.messageId ?: 0,
|
||||||
sender = it.sender.orEmpty(),
|
sender = it.sender.orEmpty(),
|
||||||
@ -58,4 +59,8 @@ class MessageRemote @Inject constructor(private val api: Api) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteMessage(message: Message): Single<Boolean> {
|
||||||
|
return api.deleteMessages(listOf(Pair(message.realId, message.folderId)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,9 @@ import io.github.wulkanowy.data.db.entities.Message
|
|||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -28,13 +30,13 @@ class MessageRepository @Inject constructor(
|
|||||||
local.getMessages(student, folder).filter { !forceRefresh }
|
local.getMessages(student, folder).filter { !forceRefresh }
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getMessages(student.studentId, folder)
|
if (it) remote.getMessages(student, folder)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getMessages(student, folder).toSingle(emptyList())
|
local.getMessages(student, folder).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteMessages(old - new)
|
local.deleteMessages(old.uniqueSubtract(new))
|
||||||
local.saveMessages((new - old)
|
local.saveMessages(new.uniqueSubtract(old)
|
||||||
.onEach {
|
.onEach {
|
||||||
it.isNotified = !notify
|
it.isNotified = !notify
|
||||||
})
|
})
|
||||||
@ -44,14 +46,14 @@ class MessageRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessage(student: Student, messageId: Int, markAsRead: Boolean = false): Single<Message> {
|
fun getMessage(student: Student, messageDbId: Long, markAsRead: Boolean = false): Single<Message> {
|
||||||
return Single.just(apiHelper.initApi(student))
|
return Single.just(apiHelper.initApi(student))
|
||||||
.flatMap { _ ->
|
.flatMap { _ ->
|
||||||
local.getMessage(student, messageId)
|
local.getMessage(messageDbId)
|
||||||
.filter { !it.content.isNullOrEmpty() }
|
.filter { !it.content.isNullOrEmpty() }
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) local.getMessage(student, messageId).toSingle()
|
if (it) local.getMessage(messageDbId).toSingle()
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}
|
}
|
||||||
.flatMap { dbMessage ->
|
.flatMap { dbMessage ->
|
||||||
@ -62,7 +64,7 @@ class MessageRepository @Inject constructor(
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getMessage(student, messageId).toSingle()
|
local.getMessage(messageDbId).toSingle()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -89,4 +91,20 @@ class MessageRepository @Inject constructor(
|
|||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun deleteMessage(message: Message): Maybe<Boolean> {
|
||||||
|
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
|
.flatMap {
|
||||||
|
if (it) remote.deleteMessage(message)
|
||||||
|
else Single.error(UnknownHostException())
|
||||||
|
}
|
||||||
|
.filter { it }
|
||||||
|
.doOnSuccess {
|
||||||
|
if (!message.removed) local.updateMessages(listOf(message.copy(removed = true).apply {
|
||||||
|
id = message.id
|
||||||
|
content = message.content
|
||||||
|
}))
|
||||||
|
else local.deleteMessages(listOf(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.db.entities.Note
|
import io.github.wulkanowy.data.db.entities.Note
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -27,8 +28,8 @@ class NoteRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getNotes(student).toSingle(emptyList())
|
local.getNotes(student).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteNotes(old - new)
|
local.deleteNotes(old.uniqueSubtract(new))
|
||||||
local.saveNotes((new - old)
|
local.saveNotes(new.uniqueSubtract(old)
|
||||||
.onEach {
|
.onEach {
|
||||||
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
|
if (it.date >= student.registrationDate.toLocalDate()) it.apply {
|
||||||
isRead = false
|
isRead = false
|
||||||
|
@ -17,12 +17,15 @@ class PreferencesRepository @Inject constructor(
|
|||||||
val isShowPresent: Boolean
|
val isShowPresent: Boolean
|
||||||
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
|
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true)
|
||||||
|
|
||||||
|
val gradeAverageMode: String
|
||||||
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_average_mode), "only_one_semester") ?: "only_one_semester"
|
||||||
|
|
||||||
val isGradeExpandable: Boolean
|
val isGradeExpandable: Boolean
|
||||||
get() = !sharedPref.getBoolean(context.getString(R.string.pref_key_expand_grade), false)
|
get() = !sharedPref.getBoolean(context.getString(R.string.pref_key_expand_grade), false)
|
||||||
|
|
||||||
val currentThemeKey: String = context.getString(R.string.pref_key_theme)
|
val appThemeKey: String = context.getString(R.string.pref_key_app_theme)
|
||||||
val currentTheme: Int
|
val appTheme: String
|
||||||
get() = sharedPref.getString(currentThemeKey, "1")?.toIntOrNull() ?: 1
|
get() = sharedPref.getString(appThemeKey, "light") ?: "light"
|
||||||
|
|
||||||
val gradeColorTheme: String
|
val gradeColorTheme: String
|
||||||
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_color_scheme), "vulcan") ?: "vulcan"
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_color_scheme), "vulcan") ?: "vulcan"
|
||||||
@ -50,8 +53,7 @@ class PreferencesRepository @Inject constructor(
|
|||||||
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0
|
||||||
|
|
||||||
val gradeMinusModifier: Double
|
val gradeMinusModifier: Double
|
||||||
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble()
|
get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble() ?: 0.0
|
||||||
?: 0.0
|
|
||||||
|
|
||||||
val fillMessageContent: Boolean
|
val fillMessageContent: Boolean
|
||||||
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_fill_message_content), true)
|
get() = sharedPref.getBoolean(context.getString(R.string.pref_key_fill_message_content), true)
|
||||||
|
@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Message
|
|||||||
import io.github.wulkanowy.data.db.entities.Recipient
|
import io.github.wulkanowy.data.db.entities.Recipient
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -31,8 +32,8 @@ class RecipientRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteRecipients(old - new)
|
local.deleteRecipients(old.uniqueSubtract(new))
|
||||||
local.saveRecipients(new - old)
|
local.saveRecipients(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getRecipients(student, role, unit).toSingle(emptyList())
|
local.getRecipients(student, role, unit).toSingle(emptyList())
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.ApiHelper
|
import io.github.wulkanowy.data.ApiHelper
|
||||||
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
import io.github.wulkanowy.data.db.entities.ReportingUnit
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -30,8 +31,8 @@ class ReportingUnitRepository @Inject constructor(
|
|||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getReportingUnits(student).toSingle(emptyList())
|
local.getReportingUnits(student).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteReportingUnits(old - new)
|
local.deleteReportingUnits(old.uniqueSubtract(new))
|
||||||
local.saveReportingUnits(new - old)
|
local.saveReportingUnits(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
}.flatMap { local.getReportingUnits(student).toSingle(emptyList()) }
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,6 @@ class SemesterLocal @Inject constructor(private val semesterDb: SemesterDao) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getSemesters(student: Student): Maybe<List<Semester>> {
|
fun getSemesters(student: Student): Maybe<List<Semester>> {
|
||||||
return semesterDb.loadAll(student.studentId).filter { !it.isEmpty() }
|
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,
|
studentId = student.studentId,
|
||||||
diaryId = semester.diaryId,
|
diaryId = semester.diaryId,
|
||||||
diaryName = semester.diaryName,
|
diaryName = semester.diaryName,
|
||||||
|
schoolYear = semester.schoolYear,
|
||||||
semesterId = semester.semesterId,
|
semesterId = semester.semesterId,
|
||||||
semesterName = semester.semesterNumber,
|
semesterName = semester.semesterNumber,
|
||||||
isCurrent = semester.current,
|
isCurrent = semester.current,
|
||||||
|
start = semester.start,
|
||||||
|
end = semester.end,
|
||||||
classId = semester.classId,
|
classId = semester.classId,
|
||||||
unitId = semester.unitId
|
unitId = semester.unitId
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.ApiHelper
|
import io.github.wulkanowy.data.ApiHelper
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -31,8 +32,8 @@ class SemesterRepository @Inject constructor(
|
|||||||
if (currentSemesters.size == 1) {
|
if (currentSemesters.size == 1) {
|
||||||
local.getSemesters(student).toSingle(emptyList())
|
local.getSemesters(student).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteSemesters(old - new)
|
local.deleteSemesters(old.uniqueSubtract(new))
|
||||||
local.saveSemesters(new - old)
|
local.saveSemesters(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.i("Current semesters list:\n${currentSemesters.joinToString(separator = "\n")}")
|
Timber.i("Current semesters list:\n${currentSemesters.joinToString(separator = "\n")}")
|
||||||
|
@ -17,8 +17,8 @@ class StudentLocal @Inject constructor(
|
|||||||
private val context: Context
|
private val context: Context
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun saveStudent(student: Student): Single<Long> {
|
fun saveStudents(students: List<Student>): Single<List<Long>> {
|
||||||
return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) }
|
return Single.fromCallable { studentDb.insertAll(students.map { it.copy(password = encrypt(it.password, context)) }) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
|
fun getStudents(decryptPass: Boolean): Maybe<List<Student>> {
|
||||||
@ -35,7 +35,7 @@ class StudentLocal @Inject constructor(
|
|||||||
return Completable.fromCallable {
|
return Completable.fromCallable {
|
||||||
studentDb.run {
|
studentDb.run {
|
||||||
resetCurrent()
|
resetCurrent()
|
||||||
updateCurrent(student.studentId)
|
updateCurrent(student.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ class StudentRemote @Inject constructor(private val api: Api) {
|
|||||||
studentName = student.studentName,
|
studentName = student.studentName,
|
||||||
schoolSymbol = student.schoolSymbol,
|
schoolSymbol = student.schoolSymbol,
|
||||||
schoolName = student.schoolName,
|
schoolName = student.schoolName,
|
||||||
|
className = student.className,
|
||||||
|
classId = student.classId,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
loginType = student.loginType.name,
|
loginType = student.loginType.name,
|
||||||
isCurrent = false,
|
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 com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.ApiHelper
|
import io.github.wulkanowy.data.ApiHelper
|
||||||
import io.github.wulkanowy.data.db.entities.Student
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
@ -21,6 +22,8 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
fun isStudentSaved(): Single<Boolean> = local.getStudents(false).isEmpty.map { !it }
|
fun isStudentSaved(): Single<Boolean> = local.getStudents(false).isEmpty.map { !it }
|
||||||
|
|
||||||
|
fun isCurrentStudentSet(): Single<Boolean> = local.getCurrentStudent(false).isEmpty.map { !it }
|
||||||
|
|
||||||
fun getStudents(email: String, password: String, endpoint: String, symbol: String = ""): Single<List<Student>> {
|
fun getStudents(email: String, password: String, endpoint: String, symbol: String = ""): Single<List<Student>> {
|
||||||
return ReactiveNetwork.checkInternetConnectivity(settings)
|
return ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
@ -36,12 +39,12 @@ class StudentRepository @Inject constructor(
|
|||||||
|
|
||||||
fun getCurrentStudent(decryptPass: Boolean = true): Single<Student> {
|
fun getCurrentStudent(decryptPass: Boolean = true): Single<Student> {
|
||||||
return local.getCurrentStudent(decryptPass)
|
return local.getCurrentStudent(decryptPass)
|
||||||
.switchIfEmpty(Maybe.error(NoSuchElementException("No current student")))
|
.switchIfEmpty(Maybe.error(NoCurrentStudentException()))
|
||||||
.toSingle()
|
.toSingle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveStudent(student: Student): Single<Long> {
|
fun saveStudents(students: List<Student>): Single<List<Long>> {
|
||||||
return local.saveStudent(student)
|
return local.saveStudents(students)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun switchStudent(student: Student): Completable {
|
fun switchStudent(student: Student): Completable {
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
|||||||
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.db.entities.Subject
|
import io.github.wulkanowy.data.db.entities.Subject
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -26,8 +27,8 @@ class SubjectRepository @Inject constructor(
|
|||||||
local.getSubjects(semester)
|
local.getSubjects(semester)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteSubjects(old - new)
|
local.deleteSubjects(old.uniqueSubtract(new))
|
||||||
local.saveSubjects(new - old)
|
local.saveSubjects(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap {
|
}.flatMap {
|
||||||
local.getSubjects(semester).toSingle(emptyList())
|
local.getSubjects(semester).toSingle(emptyList())
|
||||||
|
@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.entities.Semester
|
|||||||
import io.github.wulkanowy.data.db.entities.Timetable
|
import io.github.wulkanowy.data.db.entities.Timetable
|
||||||
import io.github.wulkanowy.utils.friday
|
import io.github.wulkanowy.utils.friday
|
||||||
import io.github.wulkanowy.utils.monday
|
import io.github.wulkanowy.utils.monday
|
||||||
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import org.threeten.bp.LocalDate
|
import org.threeten.bp.LocalDate
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
@ -25,17 +26,16 @@ class TimetableRepository @Inject constructor(
|
|||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
|
||||||
if (it) remote.getTimetable(semester, monday, friday)
|
if (it) remote.getTimetable(semester, monday, friday)
|
||||||
else Single.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { newTimetable ->
|
}.flatMap { new ->
|
||||||
local.getTimetable(semester, monday, friday)
|
local.getTimetable(semester, monday, friday)
|
||||||
.toSingle(emptyList())
|
.toSingle(emptyList())
|
||||||
.doOnSuccess { oldTimetable ->
|
.doOnSuccess { old ->
|
||||||
local.deleteTimetable(oldTimetable - newTimetable)
|
local.deleteTimetable(old.uniqueSubtract(new))
|
||||||
local.saveTimetable((newTimetable - oldTimetable).map { item ->
|
local.saveTimetable(new.uniqueSubtract(old).map { item ->
|
||||||
item.apply {
|
item.apply {
|
||||||
oldTimetable.singleOrNull { this.start == it.start }?.let {
|
old.singleOrNull { this.start == it.start }?.let {
|
||||||
return@map copy(
|
return@map copy(
|
||||||
room = if (room.isEmpty()) it.room else room,
|
room = if (room.isEmpty()) it.room else room
|
||||||
teacher = if (teacher.isEmpty()) it.teacher else teacher
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,6 @@ import javax.inject.Singleton
|
|||||||
BuilderModule::class])
|
BuilderModule::class])
|
||||||
interface AppComponent : AndroidInjector<WulkanowyApp> {
|
interface AppComponent : AndroidInjector<WulkanowyApp> {
|
||||||
|
|
||||||
@Component.Builder
|
@Component.Factory
|
||||||
abstract class Builder : AndroidInjector.Builder<WulkanowyApp>()
|
interface Factory : AndroidInjector.Factory<WulkanowyApp>
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.BuildConfig.DEBUG
|
import io.github.wulkanowy.BuildConfig.DEBUG
|
||||||
import io.github.wulkanowy.WulkanowyApp
|
import io.github.wulkanowy.WulkanowyApp
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -30,11 +29,11 @@ internal class AppModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideFirebaseAnalyticsHelper(context: Context) = FirebaseAnalyticsHelper(FirebaseAnalytics.getInstance(context))
|
fun provideFirebaseAnalytics(context: Context) = FirebaseAnalytics.getInstance(context)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideAppWidgetManager(context: Context) = AppWidgetManager.getInstance(context)
|
fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context)
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("isDebug")
|
@Named("isDebug")
|
||||||
|
@ -5,11 +5,14 @@ import dagger.android.ContributesAndroidInjector
|
|||||||
import io.github.wulkanowy.di.scopes.PerActivity
|
import io.github.wulkanowy.di.scopes.PerActivity
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginModule
|
import io.github.wulkanowy.ui.modules.login.LoginModule
|
||||||
|
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainModule
|
import io.github.wulkanowy.ui.modules.main.MainModule
|
||||||
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
|
||||||
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
import io.github.wulkanowy.ui.modules.splash.SplashActivity
|
||||||
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetProvider
|
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetProvider
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureActivity
|
||||||
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
internal abstract class BuilderModule {
|
internal abstract class BuilderModule {
|
||||||
@ -29,6 +32,15 @@ internal abstract class BuilderModule {
|
|||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindMessageSendActivity(): SendMessageActivity
|
abstract fun bindMessageSendActivity(): SendMessageActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindTimetableWidgetAccountActivity(): TimetableWidgetConfigureActivity
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
|
abstract fun bindTimetableWidgetProvider(): TimetableWidgetProvider
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindLuckyNumberWidgetAccountActivity(): LuckyNumberWidgetConfigureActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun bindLuckyNumberWidgetProvider(): LuckyNumberWidgetProvider
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class SyncManager @Inject constructor(
|
|||||||
fun startSyncWorker(restart: Boolean = false) {
|
fun startSyncWorker(restart: Boolean = false) {
|
||||||
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
|
if (preferencesRepository.isServiceEnabled && !now().isHolidays) {
|
||||||
workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
|
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)
|
.setBackoffCriteria(EXPONENTIAL, 30, MINUTES)
|
||||||
.setConstraints(Constraints.Builder()
|
.setConstraints(Constraints.Builder()
|
||||||
.setRequiredNetworkType(if (preferencesRepository.isServicesOnlyWifi) METERED else UNMETERED)
|
.setRequiredNetworkType(if (preferencesRepository.isServicesOnlyWifi) METERED else UNMETERED)
|
||||||
|
@ -19,7 +19,6 @@ import io.github.wulkanowy.services.sync.channels.DebugChannel
|
|||||||
import io.github.wulkanowy.services.sync.works.Work
|
import io.github.wulkanowy.services.sync.works.Work
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import io.reactivex.Flowable
|
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
@ -36,18 +35,18 @@ class SyncWorker @AssistedInject constructor(
|
|||||||
|
|
||||||
override fun createWork(): Single<Result> {
|
override fun createWork(): Single<Result> {
|
||||||
Timber.i("SyncWorker is starting")
|
Timber.i("SyncWorker is starting")
|
||||||
return studentRepository.isStudentSaved()
|
return studentRepository.isCurrentStudentSet()
|
||||||
.filter { true }
|
.filter { true }
|
||||||
.flatMap { studentRepository.getCurrentStudent().toMaybe() }
|
.flatMap { studentRepository.getCurrentStudent().toMaybe() }
|
||||||
.flatMapCompletable { student ->
|
.flatMapCompletable { student ->
|
||||||
semesterRepository.getCurrentSemester(student, true)
|
semesterRepository.getCurrentSemester(student, true)
|
||||||
.flatMapCompletable { semester ->
|
.flatMapCompletable { semester ->
|
||||||
Completable.mergeDelayError(Flowable.fromIterable(works.map { work ->
|
Completable.mergeDelayError(works.map { work ->
|
||||||
work.create(student, semester)
|
work.create(student, semester)
|
||||||
.doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") }
|
.doOnSubscribe { Timber.i("${work::class.java.simpleName} is starting") }
|
||||||
.doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") }
|
.doOnError { Timber.i("${work::class.java.simpleName} result: An exception occurred") }
|
||||||
.doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") }
|
.doOnComplete { Timber.i("${work::class.java.simpleName} result: Success") }
|
||||||
}), 3)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toSingleDefault(Result.success())
|
.toSingleDefault(Result.success())
|
||||||
|
@ -15,7 +15,7 @@ import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,8 +47,8 @@ class GradeWork @Inject constructor(
|
|||||||
.setDefaults(DEFAULT_ALL)
|
.setDefaults(DEFAULT_ALL)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.GRADE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 0), FLAG_UPDATE_CURRENT))
|
MainActivity.getStartIntent(context, MenuView.GRADE, true), FLAG_UPDATE_CURRENT))
|
||||||
.setStyle(NotificationCompat.InboxStyle().run {
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
|
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
|
||||||
grades.forEach { addLine("${it.subject}: ${it.entry}") }
|
grades.forEach { addLine("${it.subject}: ${it.entry}") }
|
||||||
|
@ -15,7 +15,7 @@ import io.github.wulkanowy.data.repositories.luckynumber.LuckyNumberRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,9 +47,8 @@ class LuckyNumberWork @Inject constructor(
|
|||||||
.setPriority(PRIORITY_HIGH)
|
.setPriority(PRIORITY_HIGH)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.MESSAGE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
|
MainActivity.getStartIntent(context, MenuView.LUCKY_NUMBER, true), FLAG_UPDATE_CURRENT))
|
||||||
)
|
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import io.github.wulkanowy.data.repositories.message.MessageRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -48,8 +48,8 @@ class MessageWork @Inject constructor(
|
|||||||
.setPriority(PRIORITY_HIGH)
|
.setPriority(PRIORITY_HIGH)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.MESSAGE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
|
MainActivity.getStartIntent(context, MenuView.MESSAGE, true), FLAG_UPDATE_CURRENT)
|
||||||
)
|
)
|
||||||
.setStyle(NotificationCompat.InboxStyle().run {
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, messages.size, messages.size))
|
setSummaryText(context.resources.getQuantityString(R.plurals.message_number_item, messages.size, messages.size))
|
||||||
|
@ -15,7 +15,7 @@ import io.github.wulkanowy.data.repositories.note.NoteRepository
|
|||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity.Companion.EXTRA_START_MENU_INDEX
|
import io.github.wulkanowy.ui.modules.main.MainView.MenuView
|
||||||
import io.github.wulkanowy.utils.getCompatColor
|
import io.github.wulkanowy.utils.getCompatColor
|
||||||
import io.reactivex.Completable
|
import io.reactivex.Completable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -47,9 +47,8 @@ class NoteWork @Inject constructor(
|
|||||||
.setPriority(PRIORITY_HIGH)
|
.setPriority(PRIORITY_HIGH)
|
||||||
.setColor(context.getCompatColor(R.color.colorPrimary))
|
.setColor(context.getCompatColor(R.color.colorPrimary))
|
||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(context, 0,
|
PendingIntent.getActivity(context, MenuView.NOTE.id,
|
||||||
MainActivity.getStartIntent(context).putExtra(EXTRA_START_MENU_INDEX, 4), FLAG_UPDATE_CURRENT)
|
MainActivity.getStartIntent(context, MenuView.NOTE, true), FLAG_UPDATE_CURRENT))
|
||||||
)
|
|
||||||
.setStyle(NotificationCompat.InboxStyle().run {
|
.setStyle(NotificationCompat.InboxStyle().run {
|
||||||
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
|
setSummaryText(context.resources.getQuantityString(R.plurals.note_number_item, notes.size, notes.size))
|
||||||
notes.forEach { addLine("${it.teacher}: ${it.category}") }
|
notes.forEach { addLine("${it.teacher}: ${it.category}") }
|
||||||
|
@ -7,7 +7,7 @@ import io.github.wulkanowy.data.db.SharedPrefHelper
|
|||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
import io.github.wulkanowy.data.repositories.timetable.TimetableRepository
|
||||||
import io.github.wulkanowy.ui.widgets.timetable.TimetableWidgetFactory
|
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetFactory
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -2,33 +2,59 @@ package io.github.wulkanowy.ui.base
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
||||||
import dagger.android.support.DaggerAppCompatActivity
|
import dagger.android.AndroidInjection
|
||||||
|
import dagger.android.DispatchingAndroidInjector
|
||||||
|
import dagger.android.support.HasSupportFragmentInjector
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.utils.FragmentLifecycleLogger
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
abstract class BaseActivity : DaggerAppCompatActivity(), BaseView {
|
abstract class BaseActivity : AppCompatActivity(), BaseView, HasSupportFragmentInjector {
|
||||||
|
|
||||||
protected lateinit var messageContainer: View
|
@Inject
|
||||||
|
lateinit var supportFragmentInjector: DispatchingAndroidInjector<Fragment>
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var fragmentLifecycleLogger: FragmentLifecycleLogger
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var themeManager: ThemeManager
|
||||||
|
|
||||||
|
protected var messageContainer: View? = null
|
||||||
|
|
||||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
AndroidInjection.inject(this)
|
||||||
|
themeManager.applyTheme(this)
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleLogger, true)
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {
|
override fun showError(text: String, error: Throwable) {
|
||||||
Snackbar.make(messageContainer, text, LENGTH_LONG).setAction(R.string.all_details) {
|
if (messageContainer != null) {
|
||||||
ErrorDialog.newInstance(error).show(supportFragmentManager, error.toString())
|
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
|
||||||
}.show()
|
.setAction(R.string.all_details) {
|
||||||
|
ErrorDialog.newInstance(error).show(supportFragmentManager, error.toString())
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
} else showMessage(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
override fun showMessage(text: String) {
|
||||||
Snackbar.make(messageContainer, text, LENGTH_LONG).show()
|
if (messageContainer != null) Snackbar.make(messageContainer!!, text, LENGTH_LONG).show()
|
||||||
|
else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
invalidateOptionsMenu()
|
invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun supportFragmentInjector() = supportFragmentInjector
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.base
|
|||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
|
|
||||||
@ -10,16 +11,22 @@ abstract class BaseFragment : DaggerFragment(), BaseView {
|
|||||||
protected var messageContainer: View? = null
|
protected var messageContainer: View? = null
|
||||||
|
|
||||||
override fun showError(text: String, error: Throwable) {
|
override fun showError(text: String, error: Throwable) {
|
||||||
if (messageContainer == null) (activity as? BaseActivity)?.showError(text, error)
|
if (messageContainer != null) {
|
||||||
else messageContainer?.also {
|
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
|
||||||
Snackbar.make(it, text, Snackbar.LENGTH_LONG).setAction(R.string.all_details) {
|
.setAction(R.string.all_details) {
|
||||||
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
if (isAdded) ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
|
||||||
}.show()
|
}
|
||||||
|
.show()
|
||||||
|
} else {
|
||||||
|
(activity as? BaseActivity)?.showError(text, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showMessage(text: String) {
|
override fun showMessage(text: String) {
|
||||||
if (messageContainer == null) (activity as? BaseActivity)?.showMessage(text)
|
if (messageContainer != null) {
|
||||||
else messageContainer?.also { Snackbar.make(it, text, Snackbar.LENGTH_LONG).show() }
|
Snackbar.make(messageContainer!!, text, LENGTH_LONG).show()
|
||||||
|
} else {
|
||||||
|
(activity as? BaseActivity)?.showMessage(text)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package io.github.wulkanowy.ui.base
|
||||||
|
|
||||||
|
import android.content.pm.PackageManager.GET_ACTIVITIES
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ThemeManager @Inject constructor(private val preferencesRepository: PreferencesRepository) {
|
||||||
|
|
||||||
|
fun applyTheme(activity: AppCompatActivity) {
|
||||||
|
if (isThemeApplicable(activity)) {
|
||||||
|
activity.delegate.apply {
|
||||||
|
when (preferencesRepository.appTheme) {
|
||||||
|
"light" -> setLocalNightMode(MODE_NIGHT_NO)
|
||||||
|
"dark" -> setLocalNightMode(MODE_NIGHT_YES)
|
||||||
|
"black" -> {
|
||||||
|
setLocalNightMode(MODE_NIGHT_YES)
|
||||||
|
activity.setTheme(R.style.WulkanowyTheme_Black)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isThemeApplicable(activity: AppCompatActivity): Boolean {
|
||||||
|
return activity.packageManager.getPackageInfo(activity.packageName, GET_ACTIVITIES)
|
||||||
|
.activities.singleOrNull { it.name == activity::class.java.canonicalName }?.theme
|
||||||
|
.let { it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package io.github.wulkanowy.ui.base.session
|
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.base.BaseFragment
|
||||||
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
import io.github.wulkanowy.ui.modules.main.MainActivity
|
||||||
|
|
||||||
open class BaseSessionFragment : BaseFragment(), BaseSessionView {
|
open class BaseSessionFragment : BaseFragment(), BaseSessionView {
|
||||||
@ -8,4 +11,11 @@ open class BaseSessionFragment : BaseFragment(), BaseSessionView {
|
|||||||
override fun showExpiredDialog() {
|
override fun showExpiredDialog() {
|
||||||
(activity as? MainActivity)?.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) {
|
override fun onAttachView(view: T) {
|
||||||
super.onAttachView(view)
|
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 {
|
interface BaseSessionView : BaseView {
|
||||||
|
|
||||||
fun showExpiredDialog()
|
fun showExpiredDialog()
|
||||||
|
|
||||||
|
fun openLoginView()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.base.session
|
|||||||
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.readystatesoftware.chuck.api.ChuckCollector
|
import com.readystatesoftware.chuck.api.ChuckCollector
|
||||||
|
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
|
||||||
import io.github.wulkanowy.ui.base.ErrorHandler
|
import io.github.wulkanowy.ui.base.ErrorHandler
|
||||||
import io.github.wulkanowy.utils.security.ScramblerException
|
import io.github.wulkanowy.utils.security.ScramblerException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -13,9 +14,12 @@ open class SessionErrorHandler @Inject constructor(
|
|||||||
|
|
||||||
var onDecryptionFail: () -> Unit = {}
|
var onDecryptionFail: () -> Unit = {}
|
||||||
|
|
||||||
|
var onNoCurrentStudent: () -> Unit = {}
|
||||||
|
|
||||||
override fun proceed(error: Throwable) {
|
override fun proceed(error: Throwable) {
|
||||||
when (error) {
|
when (error) {
|
||||||
is ScramblerException -> onDecryptionFail()
|
is ScramblerException -> onDecryptionFail()
|
||||||
|
is NoCurrentStudentException -> onNoCurrentStudent()
|
||||||
else -> super.proceed(error)
|
else -> super.proceed(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,5 +27,6 @@ open class SessionErrorHandler @Inject constructor(
|
|||||||
override fun clear() {
|
override fun clear() {
|
||||||
super.clear()
|
super.clear()
|
||||||
onDecryptionFail = {}
|
onDecryptionFail = {}
|
||||||
|
onNoCurrentStudent = {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import io.github.wulkanowy.BuildConfig
|
|||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.main.MainView
|
import io.github.wulkanowy.ui.modules.main.MainView
|
||||||
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
import io.github.wulkanowy.utils.withOnExtraListener
|
import io.github.wulkanowy.utils.withOnExtraListener
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
|||||||
.withFields(R.string::class.java.fields)
|
.withFields(R.string::class.java.fields)
|
||||||
.withCheckCachedDetection(false)
|
.withCheckCachedDetection(false)
|
||||||
.withExcludedLibraries("fastadapter", "AndroidIconics", "Jsoup", "Retrofit", "okio",
|
.withExcludedLibraries("fastadapter", "AndroidIconics", "Jsoup", "Retrofit", "okio",
|
||||||
"OkHttp", "Butterknife", "CircleImageView")
|
"Butterknife", "CircleImageView")
|
||||||
.withOnExtraListener { presenter.onExtraSelect(it) })
|
.withOnExtraListener { presenter.onExtraSelect(it) })
|
||||||
}.let {
|
}.let {
|
||||||
fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it)
|
fragmentCompat.onCreateView(inflater.context, inflater, container, savedInstanceState, it)
|
||||||
@ -57,11 +58,11 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openDiscordInviteView() {
|
override fun openDiscordInviteView() {
|
||||||
startActivity(Intent.parseUri("https://discord.gg/vccAQBr", 0))
|
context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openHomepageWebView() {
|
override fun openHomepageWebView() {
|
||||||
startActivity(Intent.parseUri("https://wulkanowy.github.io/", 0))
|
context?.openInternetBrowser("https://wulkanowy.github.io/", ::showMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openEmailClientView() {
|
override fun openEmailClientView() {
|
||||||
@ -80,7 +81,7 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
|
|||||||
if (intent.resolveActivity(it.packageManager) != null) {
|
if (intent.resolveActivity(it.packageManager) != null) {
|
||||||
startActivity(Intent.createChooser(intent, getString(R.string.about_feedback)))
|
startActivity(Intent.createChooser(intent, getString(R.string.about_feedback)))
|
||||||
} else {
|
} else {
|
||||||
startActivity(Intent.parseUri("https://github.com/wulkanowy/wulkanowy/issues", 0))
|
it.openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class AboutPresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: AboutView) {
|
override fun onAttachView(view: AboutView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("About view is attached")
|
Timber.i("About view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onExtraSelect(type: Libs.SpecialButton?) {
|
fun onExtraSelect(type: Libs.SpecialButton?) {
|
||||||
|
@ -15,7 +15,6 @@ import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
|||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.ui.modules.main.MainActivity
|
|
||||||
import io.github.wulkanowy.utils.setOnItemClickListener
|
import io.github.wulkanowy.utils.setOnItemClickListener
|
||||||
import kotlinx.android.synthetic.main.dialog_account.*
|
import kotlinx.android.synthetic.main.dialog_account.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -97,11 +96,8 @@ class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun recreateView() {
|
override fun recreateMainView() {
|
||||||
activity?.also {
|
activity?.recreate()
|
||||||
startActivity(MainActivity.getStartIntent(it))
|
|
||||||
it.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.github.wulkanowy.ui.modules.account
|
package io.github.wulkanowy.ui.modules.account
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
@ -18,9 +19,10 @@ class AccountItem(val student: Student) : AbstractFlexibleItem<AccountItem.ViewH
|
|||||||
return ViewHolder(view, adapter)
|
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 {
|
holder.apply {
|
||||||
accountItemName.text = student.studentName
|
accountItemName.text = "${student.studentName} ${student.className}"
|
||||||
accountItemSchool.text = student.schoolName
|
accountItemSchool.text = student.schoolName
|
||||||
accountItemImage.setBackgroundResource(if (student.isCurrent) R.drawable.ic_account_circular_border else 0)
|
accountItemImage.setBackgroundResource(if (student.isCurrent) R.drawable.ic_account_circular_border else 0)
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ class AccountPresenter @Inject constructor(
|
|||||||
|
|
||||||
override fun onAttachView(view: AccountView) {
|
override fun onAttachView(view: AccountView) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Account dialog is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Account dialog view was initialized")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class AccountPresenter @Inject constructor(
|
|||||||
openClearLoginView()
|
openClearLoginView()
|
||||||
} else {
|
} else {
|
||||||
Timber.i("Logout result: Switch to another student")
|
Timber.i("Logout result: Switch to another student")
|
||||||
recreateView()
|
recreateMainView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
@ -73,9 +73,10 @@ class AccountPresenter @Inject constructor(
|
|||||||
disposable.add(studentRepository.switchStudent(item.student)
|
disposable.add(studentRepository.switchStudent(item.student)
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
|
.doFinally { view?.dismissView() }
|
||||||
.subscribe({
|
.subscribe({
|
||||||
Timber.i("Change a student result: Success")
|
Timber.i("Change a student result: Success")
|
||||||
view?.recreateView()
|
view?.recreateMainView()
|
||||||
}, {
|
}, {
|
||||||
Timber.i("Change a student result: An exception occurred")
|
Timber.i("Change a student result: An exception occurred")
|
||||||
errorHandler.dispatch(it)
|
errorHandler.dispatch(it)
|
||||||
|
@ -16,6 +16,6 @@ interface AccountView : BaseView {
|
|||||||
|
|
||||||
fun openClearLoginView()
|
fun openClearLoginView()
|
||||||
|
|
||||||
fun recreateView()
|
fun recreateMainView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +77,12 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC
|
|||||||
attendanceNextButton.setOnClickListener { presenter.onNextDay() }
|
attendanceNextButton.setOnClickListener { presenter.onNextDay() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_attendance, menu)
|
inflater.inflate(R.menu.action_menu_attendance, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.attendanceMenuSummary) presenter.onSummarySwitchSelected()
|
return if (item.itemId == R.id.attendanceMenuSummary) presenter.onSummarySwitchSelected()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class AttendanceFragment : BaseSessionFragment(), AttendanceView, MainView.MainC
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFragmentReselected() {
|
override fun onFragmentReselected() {
|
||||||
presenter.onViewReselected()
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popView() {
|
override fun popView() {
|
||||||
|
@ -37,8 +37,8 @@ class AttendancePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: AttendanceView, date: Long?) {
|
fun onAttachView(view: AttendanceView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Attendance view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Attendance view was initialized")
|
||||||
loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay()))
|
loadData(ofEpochDay(date ?: now().previousOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ class AttendanceSummaryPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) {
|
fun onAttachView(view: AttendanceSummaryView, subjectId: Int?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Attendance summary view is attached with subject id ${subjectId ?: -1}")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Attendance summary view was initialized with subject id ${subjectId ?: -1}")
|
||||||
loadData(subjectId ?: -1)
|
loadData(subjectId ?: -1)
|
||||||
loadSubjects()
|
loadSubjects()
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class ExamFragment : BaseSessionFragment(), ExamView, MainView.MainChildView, Ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFragmentReselected() {
|
override fun onFragmentReselected() {
|
||||||
presenter.onViewReselected()
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showEmpty(show: Boolean) {
|
override fun showEmpty(show: Boolean) {
|
||||||
|
@ -36,8 +36,8 @@ class ExamPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: ExamView, date: Long?) {
|
fun onAttachView(view: ExamView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Exam view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Exam view was initialized")
|
||||||
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
loadData(ofEpochDay(date ?: now().nextOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.grade
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
|
import io.github.wulkanowy.data.db.entities.Student
|
||||||
|
import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
||||||
|
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
||||||
|
import io.github.wulkanowy.utils.calcAverage
|
||||||
|
import io.github.wulkanowy.utils.changeModifier
|
||||||
|
import io.reactivex.Single
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GradeAverageProvider @Inject constructor(
|
||||||
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val gradeRepository: GradeRepository
|
||||||
|
) {
|
||||||
|
fun getGradeAverage(student: Student, semesters: List<Semester>, selectedSemesterId: Int, forceRefresh: Boolean): Single<Map<String, Double>> {
|
||||||
|
return when (preferencesRepository.gradeAverageMode) {
|
||||||
|
"all_year" -> getAllYearAverage(student, semesters, selectedSemesterId, forceRefresh)
|
||||||
|
"only_one_semester" -> getOnlyOneSemesterAverage(student, semesters, selectedSemesterId, forceRefresh)
|
||||||
|
else -> throw IllegalArgumentException("Incorrect grade average mode: ${preferencesRepository.gradeAverageMode} ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAllYearAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Single<Map<String, Double>> {
|
||||||
|
val selectedSemester = semesters.single { it.semesterId == semesterId }
|
||||||
|
val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 }
|
||||||
|
val plusModifier = preferencesRepository.gradePlusModifier
|
||||||
|
val minusModifier = preferencesRepository.gradeMinusModifier
|
||||||
|
|
||||||
|
return gradeRepository.getGrades(student, selectedSemester, forceRefresh)
|
||||||
|
.flatMap { firstGrades ->
|
||||||
|
if (selectedSemester == firstSemester) Single.just(firstGrades)
|
||||||
|
else gradeRepository.getGrades(student, firstSemester)
|
||||||
|
.map { secondGrades -> secondGrades + firstGrades }
|
||||||
|
}.map { grades ->
|
||||||
|
grades.map { it.changeModifier(plusModifier, minusModifier) }
|
||||||
|
.groupBy { it.subject }
|
||||||
|
.mapValues { it.value.calcAverage() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOnlyOneSemesterAverage(student: Student, semesters: List<Semester>, semesterId: Int, forceRefresh: Boolean): Single<Map<String, Double>> {
|
||||||
|
val selectedSemester = semesters.single { it.semesterId == semesterId }
|
||||||
|
val plusModifier = preferencesRepository.gradePlusModifier
|
||||||
|
val minusModifier = preferencesRepository.gradeMinusModifier
|
||||||
|
|
||||||
|
return gradeRepository.getGrades(student, selectedSemester, forceRefresh)
|
||||||
|
.map { grades ->
|
||||||
|
grades.map { it.changeModifier(plusModifier, minusModifier) }
|
||||||
|
.groupBy { it.subject }
|
||||||
|
.mapValues { it.value.calcAverage() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,9 +57,9 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
|||||||
presenter.onAttachView(this, savedInstanceState?.getInt(SAVED_SEMESTER_KEY))
|
presenter.onAttachView(this, savedInstanceState?.getInt(SAVED_SEMESTER_KEY))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_grade, menu)
|
inflater.inflate(R.menu.action_menu_grade, menu)
|
||||||
semesterSwitchMenu = menu?.findItem(R.id.gradeMenuSemester)
|
semesterSwitchMenu = menu.findItem(R.id.gradeMenuSemester)
|
||||||
presenter.onCreateMenu()
|
presenter.onCreateMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,13 +82,13 @@ class GradeFragment : BaseSessionFragment(), GradeView, MainView.MainChildView,
|
|||||||
gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
gradeSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.gradeMenuSemester) presenter.onSemesterSwitch()
|
return if (item.itemId == R.id.gradeMenuSemester) presenter.onSemesterSwitch()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFragmentReselected() {
|
override fun onFragmentReselected() {
|
||||||
presenter.onViewReselected()
|
if (::presenter.isInitialized) presenter.onViewReselected()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
override fun showContent(show: Boolean) {
|
||||||
|
@ -27,12 +27,12 @@ class GradePresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
fun onAttachView(view: GradeView, savedIndex: Int?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Grade view is attached")
|
|
||||||
selectedIndex = savedIndex ?: 0
|
selectedIndex = savedIndex ?: 0
|
||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
}
|
}
|
||||||
|
Timber.i("Grade view was initialized with $selectedIndex index")
|
||||||
loadData()
|
loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +67,8 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
|
|||||||
presenter.onAttachView(this)
|
presenter.onAttachView(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater?.inflate(R.menu.action_menu_grade_details, menu)
|
inflater.inflate(R.menu.action_menu_grade_details, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
@ -88,8 +88,8 @@ class GradeDetailsFragment : BaseSessionFragment(), GradeDetailsView, GradeView.
|
|||||||
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
gradeDetailsSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return if (item?.itemId == R.id.gradeDetailsMenuRead) presenter.onMarkAsReadSelected()
|
return if (item.itemId == R.id.gradeDetailsMenuRead) presenter.onMarkAsReadSelected()
|
||||||
else false
|
else false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,9 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
|||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.calcAverage
|
|
||||||
import io.github.wulkanowy.utils.changeModifier
|
|
||||||
import io.github.wulkanowy.utils.getBackgroundColor
|
import io.github.wulkanowy.utils.getBackgroundColor
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -23,6 +22,7 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
private val studentRepository: StudentRepository,
|
private val studentRepository: StudentRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val preferencesRepository: PreferencesRepository,
|
||||||
|
private val averageProvider: GradeAverageProvider,
|
||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BaseSessionPresenter<GradeDetailsView>(errorHandler) {
|
) : BaseSessionPresenter<GradeDetailsView>(errorHandler) {
|
||||||
|
|
||||||
@ -109,11 +109,16 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
private fun loadData(semesterId: Int, forceRefresh: Boolean) {
|
||||||
Timber.i("Loading grade details data started")
|
Timber.i("Loading grade details data started")
|
||||||
disposable.add(studentRepository.getCurrentStudent()
|
disposable.add(studentRepository.getCurrentStudent()
|
||||||
.flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } }
|
.flatMap { semesterRepository.getSemesters(it).map { semester -> it to semester } }
|
||||||
.flatMap { gradeRepository.getGrades(it.second, it.first.first { item -> item.semesterId == semesterId }, forceRefresh) }
|
.flatMap { (student, semesters) ->
|
||||||
.map { it.sortedByDescending { grade -> grade.date } }
|
averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh)
|
||||||
.map { it.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) } }
|
.flatMap { averages ->
|
||||||
.map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) }
|
gradeRepository.getGrades(student, semesters.first { semester -> semester.semesterId == semesterId })
|
||||||
|
.map { it.sortedByDescending { grade -> grade.date } }
|
||||||
|
.map { it.groupBy { grade -> grade.subject }.toSortedMap() }
|
||||||
|
.map { createGradeItems(it, averages) }
|
||||||
|
}
|
||||||
|
}
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
.doFinally {
|
.doFinally {
|
||||||
@ -139,32 +144,36 @@ class GradeDetailsPresenter @Inject constructor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createGradeItems(items: Map<String, List<Grade>>): List<GradeDetailsHeader> {
|
private fun createGradeItems(items: Map<String, List<Grade>>, averages: Map<String, Double>): List<GradeDetailsHeader> {
|
||||||
|
val isGradeExpandable = preferencesRepository.isGradeExpandable
|
||||||
|
val gradeColorTheme = preferencesRepository.gradeColorTheme
|
||||||
|
|
||||||
|
val noDescriptionString = view?.noDescriptionString.orEmpty()
|
||||||
|
val weightString = view?.weightString.orEmpty()
|
||||||
|
|
||||||
return items.map {
|
return items.map {
|
||||||
it.value.calcAverage().let { average ->
|
GradeDetailsHeader(
|
||||||
GradeDetailsHeader(
|
subject = it.key,
|
||||||
subject = it.key,
|
average = formatAverage(averages[it.key]),
|
||||||
average = formatAverage(average),
|
number = view?.getGradeNumberString(it.value.size).orEmpty(),
|
||||||
number = view?.getGradeNumberString(it.value.size).orEmpty(),
|
newGrades = it.value.filter { grade -> !grade.isRead }.size,
|
||||||
newGrades = it.value.filter { grade -> !grade.isRead }.size,
|
isExpandable = isGradeExpandable
|
||||||
isExpandable = preferencesRepository.isGradeExpandable
|
).apply {
|
||||||
).apply {
|
subItems = it.value.map { item ->
|
||||||
subItems = it.value.map { item ->
|
GradeDetailsItem(
|
||||||
GradeDetailsItem(
|
grade = item,
|
||||||
grade = item,
|
valueBgColor = item.getBackgroundColor(gradeColorTheme),
|
||||||
valueBgColor = item.getBackgroundColor(preferencesRepository.gradeColorTheme),
|
weightString = weightString,
|
||||||
weightString = view?.weightString.orEmpty(),
|
noDescriptionString = noDescriptionString
|
||||||
noDescriptionString = view?.noDescriptionString.orEmpty()
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun formatAverage(average: Double): String {
|
private fun formatAverage(average: Double?): String {
|
||||||
return view?.run {
|
return view?.run {
|
||||||
if (average == 0.0) emptyAverageString
|
if (average == null || average == .0) emptyAverageString
|
||||||
else averageString.format(average)
|
else averageString.format(average)
|
||||||
}.orEmpty()
|
}.orEmpty()
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
package io.github.wulkanowy.ui.modules.grade.summary
|
package io.github.wulkanowy.ui.modules.grade.summary
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||||
import io.github.wulkanowy.data.repositories.grade.GradeRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
|
import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository
|
||||||
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
|
|
||||||
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
import io.github.wulkanowy.data.repositories.semester.SemesterRepository
|
||||||
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
import io.github.wulkanowy.data.repositories.student.StudentRepository
|
||||||
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
import io.github.wulkanowy.ui.base.session.BaseSessionPresenter
|
||||||
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
import io.github.wulkanowy.ui.base.session.SessionErrorHandler
|
||||||
|
import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider
|
||||||
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
|
||||||
import io.github.wulkanowy.utils.SchedulersProvider
|
import io.github.wulkanowy.utils.SchedulersProvider
|
||||||
import io.github.wulkanowy.utils.calcAverage
|
import io.github.wulkanowy.utils.calcAverage
|
||||||
import io.github.wulkanowy.utils.changeModifier
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.String.format
|
import java.lang.String.format
|
||||||
import java.util.Locale.FRANCE
|
import java.util.Locale.FRANCE
|
||||||
@ -20,10 +18,9 @@ import javax.inject.Inject
|
|||||||
class GradeSummaryPresenter @Inject constructor(
|
class GradeSummaryPresenter @Inject constructor(
|
||||||
private val errorHandler: SessionErrorHandler,
|
private val errorHandler: SessionErrorHandler,
|
||||||
private val gradeSummaryRepository: GradeSummaryRepository,
|
private val gradeSummaryRepository: GradeSummaryRepository,
|
||||||
private val gradeRepository: GradeRepository,
|
|
||||||
private val studentRepository: StudentRepository,
|
private val studentRepository: StudentRepository,
|
||||||
private val semesterRepository: SemesterRepository,
|
private val semesterRepository: SemesterRepository,
|
||||||
private val preferencesRepository: PreferencesRepository,
|
private val averageProvider: GradeAverageProvider,
|
||||||
private val schedulers: SchedulersProvider,
|
private val schedulers: SchedulersProvider,
|
||||||
private val analytics: FirebaseAnalyticsHelper
|
private val analytics: FirebaseAnalyticsHelper
|
||||||
) : BaseSessionPresenter<GradeSummaryView>(errorHandler) {
|
) : BaseSessionPresenter<GradeSummaryView>(errorHandler) {
|
||||||
@ -36,25 +33,13 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) {
|
||||||
Timber.i("Loading grade summary data started")
|
Timber.i("Loading grade summary data started")
|
||||||
disposable.add(studentRepository.getCurrentStudent()
|
disposable.add(studentRepository.getCurrentStudent()
|
||||||
.flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } }
|
.flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } }
|
||||||
.map { pair -> pair.first.first { it.semesterId == semesterId } to pair.second }
|
.flatMap { (student, semesters) ->
|
||||||
.flatMap {
|
gradeSummaryRepository.getGradesSummary(semesters.first { it.semesterId == semesterId }, forceRefresh)
|
||||||
gradeSummaryRepository.getGradesSummary(it.first, forceRefresh)
|
.map { it.sortedBy { subject -> subject.subject } }
|
||||||
.flatMap { gradesSummary ->
|
.flatMap { gradesSummary ->
|
||||||
gradeRepository.getGrades(it.second, it.first, forceRefresh)
|
averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh)
|
||||||
.map { grades ->
|
.map { averages -> createGradeSummaryItemsAndHeader(gradesSummary, averages) }
|
||||||
grades.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) }
|
|
||||||
.groupBy { grade -> grade.subject }
|
|
||||||
.mapValues { entry -> entry.value.calcAverage() }
|
|
||||||
.filterValues { value -> value != 0.0 }
|
|
||||||
.let { averages ->
|
|
||||||
createGradeSummaryItems(gradesSummary, averages) to
|
|
||||||
GradeSummaryScrollableHeader(
|
|
||||||
formatAverage(gradesSummary.calcAverage()),
|
|
||||||
formatAverage(averages.values.average())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
@ -66,14 +51,14 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
enableSwipe(true)
|
enableSwipe(true)
|
||||||
notifyParentDataLoaded(semesterId)
|
notifyParentDataLoaded(semesterId)
|
||||||
}
|
}
|
||||||
}.subscribe({
|
}.subscribe({ (gradeSummaryItems, gradeSummaryHeader) ->
|
||||||
Timber.i("Loading grade summary result: Success")
|
Timber.i("Loading grade summary result: Success")
|
||||||
view?.run {
|
view?.run {
|
||||||
showEmpty(it.first.isEmpty())
|
showEmpty(gradeSummaryItems.isEmpty())
|
||||||
showContent(it.first.isNotEmpty())
|
showContent(gradeSummaryItems.isNotEmpty())
|
||||||
updateData(it.first, it.second)
|
updateData(gradeSummaryItems, gradeSummaryHeader)
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_grade_summary", "items" to it.first.size, "force_refresh" to forceRefresh)
|
analytics.logEvent("load_grade_summary", "items" to gradeSummaryItems.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
Timber.i("Loading grade summary result: An exception occurred")
|
Timber.i("Loading grade summary result: An exception occurred")
|
||||||
view?.run { showEmpty(isViewEmpty) }
|
view?.run { showEmpty(isViewEmpty) }
|
||||||
@ -104,16 +89,24 @@ class GradeSummaryPresenter @Inject constructor(
|
|||||||
disposable.clear()
|
disposable.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createGradeSummaryItems(gradesSummary: List<GradeSummary>, averages: Map<String, Double>)
|
private fun createGradeSummaryItemsAndHeader(gradesSummary: List<GradeSummary>, averages: Map<String, Double>)
|
||||||
: List<GradeSummaryItem> {
|
: Pair<List<GradeSummaryItem>, GradeSummaryScrollableHeader> {
|
||||||
return gradesSummary.filter { !checkEmpty(it, averages) }.map { it ->
|
return averages.filterValues { value -> value != 0.0 }
|
||||||
GradeSummaryItem(
|
.let { filteredAverages ->
|
||||||
title = it.subject,
|
gradesSummary.filter { !checkEmpty(it, filteredAverages) }
|
||||||
average = formatAverage(averages.getOrElse(it.subject) { 0.0 }, ""),
|
.map {
|
||||||
predictedGrade = it.predictedGrade,
|
GradeSummaryItem(
|
||||||
finalGrade = it.finalGrade
|
title = it.subject,
|
||||||
)
|
average = formatAverage(filteredAverages.getOrElse(it.subject) { 0.0 }, ""),
|
||||||
}
|
predictedGrade = it.predictedGrade,
|
||||||
|
finalGrade = it.finalGrade
|
||||||
|
)
|
||||||
|
}.let {
|
||||||
|
it to GradeSummaryScrollableHeader(
|
||||||
|
formatAverage(gradesSummary.calcAverage()),
|
||||||
|
formatAverage(filteredAverages.values.average()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkEmpty(gradeSummary: GradeSummary, averages: Map<String, Double>): Boolean {
|
private fun checkEmpty(gradeSummary: GradeSummary, averages: Map<String, Double>): Boolean {
|
||||||
|
@ -34,8 +34,8 @@ class HomeworkPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onAttachView(view: HomeworkView, date: Long?) {
|
fun onAttachView(view: HomeworkView, date: Long?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
Timber.i("Homework view is attached")
|
|
||||||
view.initView()
|
view.initView()
|
||||||
|
Timber.i("Homework view was initialized")
|
||||||
loadData(LocalDate.ofEpochDay(date ?: LocalDate.now().nextOrSameSchoolDay.toEpochDay()))
|
loadData(LocalDate.ofEpochDay(date ?: LocalDate.now().nextOrSameSchoolDay.toEpochDay()))
|
||||||
reloadView()
|
reloadView()
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ class LoginPresenter @Inject constructor(errorHandler: ErrorHandler) : BasePrese
|
|||||||
initAdapter()
|
initAdapter()
|
||||||
showActionBar(false)
|
showActionBar(false)
|
||||||
}
|
}
|
||||||
Timber.i("Login view is attached")
|
Timber.i("Login view was initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onFormViewAccountLogged(students: List<Student>, loginData: Triple<String, String, String>) {
|
fun onFormViewAccountLogged(students: List<Student>, loginData: Triple<String, String, String>) {
|
||||||
|
@ -16,6 +16,7 @@ import io.github.wulkanowy.data.db.entities.Student
|
|||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||||
import io.github.wulkanowy.utils.hideSoftInput
|
import io.github.wulkanowy.utils.hideSoftInput
|
||||||
|
import io.github.wulkanowy.utils.openInternetBrowser
|
||||||
import io.github.wulkanowy.utils.setOnItemSelectedListener
|
import io.github.wulkanowy.utils.setOnItemSelectedListener
|
||||||
import io.github.wulkanowy.utils.setOnTextChangedListener
|
import io.github.wulkanowy.utils.setOnTextChangedListener
|
||||||
import io.github.wulkanowy.utils.showSoftInput
|
import io.github.wulkanowy.utils.showSoftInput
|
||||||
@ -53,7 +54,8 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
loginFormName.setOnTextChangedListener { presenter.onNameTextChanged() }
|
loginFormName.setOnTextChangedListener { presenter.onNameTextChanged() }
|
||||||
loginFormPass.setOnTextChangedListener { presenter.onPassTextChanged() }
|
loginFormPass.setOnTextChangedListener { presenter.onPassTextChanged() }
|
||||||
loginFormHost.setOnItemSelectedListener { presenter.onHostSelected() }
|
loginFormHost.setOnItemSelectedListener { presenter.onHostSelected() }
|
||||||
loginFormSignIn.setOnClickListener { presenter.attemptLogin() }
|
loginFormSignIn.setOnClickListener { presenter.onSignInClick() }
|
||||||
|
loginFormPrivacyLink.setOnClickListener { presenter.onPrivacyLinkClick() }
|
||||||
|
|
||||||
loginFormPass.setOnEditorActionListener { _, id, _ ->
|
loginFormPass.setOnEditorActionListener { _, id, _ ->
|
||||||
if (id == IME_ACTION_DONE || id == IME_NULL) loginFormSignIn.callOnClick() else false
|
if (id == IME_ACTION_DONE || id == IME_NULL) loginFormSignIn.callOnClick() else false
|
||||||
@ -130,6 +132,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showPrivacyPolicy() {
|
||||||
|
loginFormPrivacyLink.visibility = VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
override fun notifyParentAccountLogged(students: List<Student>) {
|
override fun notifyParentAccountLogged(students: List<Student>) {
|
||||||
(activity as? LoginActivity)?.onFormFragmentAccountLogged(students, Triple(
|
(activity as? LoginActivity)?.onFormFragmentAccountLogged(students, Triple(
|
||||||
loginFormName.text.toString(),
|
loginFormName.text.toString(),
|
||||||
@ -138,6 +144,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun openPrivacyPolicyPage() {
|
||||||
|
context?.openInternetBrowser("https://wulkanowy.github.io/polityka-prywatnosci.html", ::showMessage)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
presenter.onDetachView()
|
presenter.onDetachView()
|
||||||
|
@ -22,7 +22,8 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
view.run {
|
view.run {
|
||||||
initView()
|
initView()
|
||||||
if (isDebug) showVersion()
|
if (isDebug) showVersion() else showPrivacyPolicy()
|
||||||
|
|
||||||
errorHandler.onBadCredentials = {
|
errorHandler.onBadCredentials = {
|
||||||
setErrorPassIncorrect()
|
setErrorPassIncorrect()
|
||||||
showSoftKeyboard()
|
showSoftKeyboard()
|
||||||
@ -31,6 +32,10 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onPrivacyLinkClick() {
|
||||||
|
view?.openPrivacyPolicyPage()
|
||||||
|
}
|
||||||
|
|
||||||
fun onHostSelected() {
|
fun onHostSelected() {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
clearPassError()
|
clearPassError()
|
||||||
@ -47,7 +52,7 @@ class LoginFormPresenter @Inject constructor(
|
|||||||
view?.clearNameError()
|
view?.clearNameError()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun attemptLogin() {
|
fun onSignInClick() {
|
||||||
val email = view?.formNameValue.orEmpty()
|
val email = view?.formNameValue.orEmpty()
|
||||||
val password = view?.formPassValue.orEmpty()
|
val password = view?.formPassValue.orEmpty()
|
||||||
val endpoint = view?.formHostValue.orEmpty()
|
val endpoint = view?.formHostValue.orEmpty()
|
||||||
|
@ -37,5 +37,9 @@ interface LoginFormView : BaseView {
|
|||||||
|
|
||||||
fun showVersion()
|
fun showVersion()
|
||||||
|
|
||||||
|
fun showPrivacyPolicy()
|
||||||
|
|
||||||
fun notifyParentAccountLogged(students: List<Student>)
|
fun notifyParentAccountLogged(students: List<Student>)
|
||||||
|
|
||||||
|
fun openPrivacyPolicyPage()
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package io.github.wulkanowy.ui.modules.login.studentselect
|
package io.github.wulkanowy.ui.modules.login.studentselect
|
||||||
|
|
||||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
||||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.VISIBLE
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
@ -45,6 +42,7 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
|
loginStudentSelectSignIn.setOnClickListener { presenter.onSignIn() }
|
||||||
loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } }
|
loginAdapter.apply { setOnItemClickListener { presenter.onItemSelected(it) } }
|
||||||
|
|
||||||
loginStudentSelectRecycler.apply {
|
loginStudentSelectRecycler.apply {
|
||||||
@ -54,14 +52,11 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(data: List<LoginStudentSelectItem>) {
|
override fun updateData(data: List<LoginStudentSelectItem>) {
|
||||||
loginAdapter.updateDataSet(data, true)
|
loginAdapter.updateDataSet(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun openMainView() {
|
override fun openMainView() {
|
||||||
activity?.let {
|
activity?.let { startActivity(MainActivity.getStartIntent(context = it, clear = true)) }
|
||||||
startActivity(MainActivity.getStartIntent(it)
|
|
||||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showProgress(show: Boolean) {
|
override fun showProgress(show: Boolean) {
|
||||||
@ -69,11 +64,11 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
override fun showContent(show: Boolean) {
|
||||||
loginStudentSelectRecycler.visibility = if (show) VISIBLE else GONE
|
loginStudentSelectContent.visibility = if (show) VISIBLE else GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showActionBar(show: Boolean) {
|
override fun enableSignIn(enable: Boolean) {
|
||||||
(activity as? AppCompatActivity)?.supportActionBar?.run { if (show) show() else hide() }
|
loginStudentSelectSignIn.isEnabled = enable
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onParentInitStudentSelectFragment(students: List<Student>) {
|
fun onParentInitStudentSelectFragment(students: List<Student>) {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user