From fa3c357665f879d90eecf667c54f6be613f0ef43 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2020 10:58:38 +0000 Subject: [PATCH 01/61] Bump work_manager from 2.3.2 to 2.3.3 (#717) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 86fe69666..1f152b02c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -110,7 +110,7 @@ play { } ext { - work_manager = "2.3.2" + work_manager = "2.3.3" room = "2.2.4" dagger = "2.26" chucker = "2.0.4" From 630439505046f6acd8955396c2fcebc4d80eff8e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2020 10:59:07 +0000 Subject: [PATCH 02/61] Bump swiperefreshlayout from 1.1.0-alpha03 to 1.1.0-beta01 (#718) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 1f152b02c..74da6e810 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -136,7 +136,7 @@ dependencies { implementation "androidx.preference:preference-ktx:1.1.0" implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "androidx.viewpager:viewpager:1.0.0" - implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03" + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-beta01" implementation "androidx.constraintlayout:constraintlayout:1.1.3" implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" implementation "com.google.android.material:material:1.1.0" From 68b26d5e2b55ca460d4157e49b1ffff20c007dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 7 Mar 2020 13:38:15 +0100 Subject: [PATCH 03/61] Update gradle-publisher to 2.7.2 (#719) --- app/src/main/res/drawable/ic_share.xml | 5 +++++ app/src/main/res/menu/action_menu_logviewer.xml | 2 +- build.gradle | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/drawable/ic_share.xml diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 000000000..045bbc0c0 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/menu/action_menu_logviewer.xml b/app/src/main/res/menu/action_menu_logviewer.xml index cb2b31a0f..84b076b15 100644 --- a/app/src/main/res/menu/action_menu_logviewer.xml +++ b/app/src/main/res/menu/action_menu_logviewer.xml @@ -3,7 +3,7 @@ Date: Sat, 14 Mar 2020 22:18:34 +0000 Subject: [PATCH 04/61] Bump mockito-android from 3.3.1 to 3.3.3 (#723) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 74da6e810..1bb9ec7aa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -198,7 +198,7 @@ dependencies { androidTestImplementation "io.mockk:mockk-android:$mockk" androidTestImplementation "androidx.room:room-testing:$room" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - androidTestImplementation "org.mockito:mockito-android:3.3.1" + androidTestImplementation "org.mockito:mockito-android:3.3.3" } apply plugin: 'com.google.gms.google-services' From 37842a3603126fd3fa7781b48cf75a6a84f9c9fe Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2020 22:19:47 +0000 Subject: [PATCH 05/61] Bump dagger from 2.26 to 2.27 (#724) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 1bb9ec7aa..a2944e3b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -112,7 +112,7 @@ play { ext { work_manager = "2.3.3" room = "2.2.4" - dagger = "2.26" + dagger = "2.27" chucker = "2.0.4" mockk = "1.9.2" } From 478596c4e67b9cc9c454661b1bf8c3e46a96eac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 14 Mar 2020 23:19:59 +0100 Subject: [PATCH 06/61] Fix marking message as read in hybrid and mobile api mode (#722) --- app/build.gradle | 2 +- .../data/repositories/message/MessageRepository.kt | 9 ++------- .../message/preview/MessagePreviewPresenter.kt | 2 -- .../ui/modules/message/tab/MessageTabPresenter.kt | 14 -------------- .../repositories/message/MessageRepositoryTest.kt | 13 +++++++++++++ 5 files changed, 16 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a2944e3b9..ddf76f83a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -122,7 +122,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:0.16.0" + implementation "io.github.wulkanowy:sdk:85d47f6" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt index 3d860a047..cf0de0d58 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt @@ -55,7 +55,7 @@ class MessageRepository @Inject constructor( .filter { it.content.isNotEmpty().also { status -> Timber.d("Message content in db empty: ${!status}") - } + } && !it.unread } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { @@ -83,10 +83,6 @@ class MessageRepository @Inject constructor( .toSingle(emptyList()) } - fun updateMessage(message: Message): Completable { - return Completable.fromCallable { local.updateMessages(listOf(message)) } - } - fun updateMessages(messages: List): Completable { return Completable.fromCallable { local.updateMessages(messages) } } @@ -99,13 +95,12 @@ class MessageRepository @Inject constructor( } } - fun deleteMessage(message: Message): Maybe { + fun deleteMessage(message: Message): Single { 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 diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 7b7404b86..24abda8ca 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -119,8 +119,6 @@ class MessagePreviewPresenter @Inject constructor( }, { error -> retryCallback = { onMessageDelete() } errorHandler.dispatch(error) - }, { - view?.showErrorView(true) }) ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt index dc199207a..a6f64c2b5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt @@ -1,7 +1,6 @@ package io.github.wulkanowy.ui.modules.message.tab import eu.davidea.flexibleadapter.items.AbstractFlexibleItem -import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.repositories.message.MessageFolder import io.github.wulkanowy.data.repositories.message.MessageRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository @@ -67,7 +66,6 @@ class MessageTabPresenter @Inject constructor( if (item.message.unread) { item.message.unread = false updateItem(item) - updateMessage(item.message) } } } @@ -119,16 +117,4 @@ class MessageTabPresenter @Inject constructor( } else showError(message, error) } } - - private fun updateMessage(message: Message) { - Timber.i("Attempt to update message ${message.id}") - disposable.add(messageRepository.updateMessage(message) - .subscribeOn(schedulers.backgroundThread) - .observeOn(schedulers.mainThread) - .subscribe({ Timber.d("Update message ${message.id} result: Success") }) - { error -> - Timber.i("Update message ${message.id} result: An exception occurred") - errorHandler.dispatch(error) - }) - } } diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt index fc3b960f1..7be870ce7 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt @@ -94,4 +94,17 @@ class MessageRepositoryTest { message.subscribe(messageObserver) messageObserver.assertError(UnknownHostException::class.java) } + + @Test + fun `get message when content in db is empty, unread and there is no internet connection`() { + val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false) + + testObservingStrategy.isInternetConnection = false + `when`(local.getMessage(123)).thenReturn(Single.just(testMessage)) + + val message = repo.getMessage(student, 123) + val messageObserver = TestObserver() + message.subscribe(messageObserver) + messageObserver.assertError(UnknownHostException::class.java) + } } From f763a42323f936d79c1f7f19c3207bbc723861fe Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2020 22:20:14 +0000 Subject: [PATCH 07/61] Bump mockito-inline from 3.3.1 to 3.3.3 (#725) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ddf76f83a..fece5fa2b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -190,7 +190,7 @@ dependencies { testImplementation "junit:junit:4.13" testImplementation "io.mockk:mockk:$mockk" testImplementation "org.threeten:threetenbp:1.4.1" - testImplementation "org.mockito:mockito-inline:3.3.1" + testImplementation "org.mockito:mockito-inline:3.3.3" androidTestImplementation "androidx.test:core:1.2.0" androidTestImplementation "androidx.test:runner:1.2.0" From 7d21babd385912a4fc305a90d5dbf0053225e80d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2020 22:25:05 +0000 Subject: [PATCH 08/61] Bump rxjava from 2.2.18 to 2.2.19 (#726) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index fece5fa2b..ff8808a2f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -167,7 +167,7 @@ dependencies { implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6" implementation "io.reactivex.rxjava2:rxandroid:2.1.1" - implementation "io.reactivex.rxjava2:rxjava:2.2.18" + implementation "io.reactivex.rxjava2:rxjava:2.2.19" implementation "com.google.code.gson:gson:2.8.6" implementation "com.jakewharton.threetenabp:threetenabp:1.2.2" From 9a83b43d57d50d43373be258bf342e4c13088821 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2020 19:52:33 +0000 Subject: [PATCH 09/61] Bump fragment-ktx from 1.2.2 to 1.2.3 (#729) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ff8808a2f..b0e88b6e8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -129,7 +129,7 @@ dependencies { implementation "androidx.activity:activity-ktx:1.1.0" implementation "androidx.appcompat:appcompat:1.1.0" implementation "androidx.appcompat:appcompat-resources:1.1.0" - implementation "androidx.fragment:fragment-ktx:1.2.2" + implementation "androidx.fragment:fragment-ktx:1.2.3" implementation "androidx.annotation:annotation:1.1.0" implementation "androidx.multidex:multidex:2.0.1" From 5dfe9cdd4f8b97e02e8332b3be3b48cf844ad730 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2020 19:52:47 +0000 Subject: [PATCH 10/61] Bump work_manager from 2.3.3 to 2.3.4 (#728) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index b0e88b6e8..0266d9e0d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -110,7 +110,7 @@ play { } ext { - work_manager = "2.3.3" + work_manager = "2.3.4" room = "2.2.4" dagger = "2.27" chucker = "2.0.4" From f94b8c9be876f2dcd5a83484b70e073d100894dd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2020 19:53:59 +0000 Subject: [PATCH 11/61] Bump threetenbp from 1.4.1 to 1.4.2 (#730) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0266d9e0d..2d914c077 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -189,7 +189,7 @@ dependencies { testImplementation "junit:junit:4.13" testImplementation "io.mockk:mockk:$mockk" - testImplementation "org.threeten:threetenbp:1.4.1" + testImplementation "org.threeten:threetenbp:1.4.2" testImplementation "org.mockito:mockito-inline:3.3.3" androidTestImplementation "androidx.test:core:1.2.0" From a85a4fe7a0b701d70527126f4e1bf3722bcc3a43 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2020 20:30:48 +0000 Subject: [PATCH 12/61] Bump kotlin_version from 1.3.70 to 1.3.71 (#732) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 7b48174e6..cc32f3163 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.70' + ext.kotlin_version = '1.3.71' repositories { mavenCentral() google() From 95a833ea851a3165ae95d0e6083308c25475c711 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2020 22:04:25 +0000 Subject: [PATCH 13/61] Bump room from 2.2.4 to 2.2.5 (#727) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 2d914c077..c5aaeb0a4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -111,7 +111,7 @@ play { ext { work_manager = "2.3.4" - room = "2.2.4" + room = "2.2.5" dagger = "2.27" chucker = "2.0.4" mockk = "1.9.2" From 0320079d0230924c9c201349e087df387170f45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 28 Mar 2020 11:44:09 +0100 Subject: [PATCH 14/61] Bump chucker from 2.0.4 to 3.1.1 (#733) --- app/build.gradle | 9 +++++---- .../debug/res/values/preferences_defaults.xml | 4 ++++ .../github/wulkanowy/data/RepositoryModule.kt | 20 ++++++++++--------- .../github/wulkanowy/ui/base/ErrorHandler.kt | 6 +++--- .../ui/modules/login/LoginErrorHandler.kt | 6 +++--- .../login/recover/RecoverErrorHandler.kt | 6 +++--- .../ui/modules/settings/SettingsPresenter.kt | 6 +++--- .../completed/CompletedLessonsErrorHandler.kt | 6 +++--- 8 files changed, 35 insertions(+), 28 deletions(-) create mode 100644 app/src/debug/res/values/preferences_defaults.xml diff --git a/app/build.gradle b/app/build.gradle index c5aaeb0a4..ef9cf8e64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -113,7 +113,8 @@ ext { work_manager = "2.3.4" room = "2.2.5" dagger = "2.27" - chucker = "2.0.4" + // don't update https://github.com/ChuckerTeam/chucker/issues/242 + chucker = "3.1.1" mockk = "1.9.2" } @@ -122,7 +123,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:85d47f6" + implementation "io.github.wulkanowy:sdk:be7ed9c" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" @@ -182,9 +183,9 @@ dependencies { playImplementation "com.google.firebase:firebase-core:17.2.3" playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1" - releaseImplementation "fr.o80.chucker:library-no-op:$chucker" + releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" - debugImplementation "fr.o80.chucker:library:$chucker" + debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker" debugImplementation "com.amitshekhar.android:debug-db:1.0.6" testImplementation "junit:junit:4.13" diff --git a/app/src/debug/res/values/preferences_defaults.xml b/app/src/debug/res/values/preferences_defaults.xml new file mode 100644 index 000000000..f5a12464f --- /dev/null +++ b/app/src/debug/res/values/preferences_defaults.xml @@ -0,0 +1,4 @@ + + + true + diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index 48e51e3ce..cb2daf685 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -7,9 +7,9 @@ import android.content.res.Resources import androidx.preference.PreferenceManager import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy -import com.readystatesoftware.chuck.api.ChuckCollector -import com.readystatesoftware.chuck.api.ChuckInterceptor -import com.readystatesoftware.chuck.api.RetentionManager +import com.chuckerteam.chucker.api.ChuckerCollector +import com.chuckerteam.chucker.api.ChuckerInterceptor +import com.chuckerteam.chucker.api.RetentionManager import dagger.Module import dagger.Provides import io.github.wulkanowy.data.db.AppDatabase @@ -32,23 +32,25 @@ internal class RepositoryModule { @Singleton @Provides - fun provideSdk(chuckCollector: ChuckCollector, context: Context): Sdk { + fun provideSdk(chuckerCollector: ChuckerCollector, context: Context): Sdk { return Sdk().apply { androidVersion = android.os.Build.VERSION.RELEASE buildTag = android.os.Build.MODEL setSimpleHttpLogger { Timber.d(it) } // for debug only - addInterceptor(ChuckInterceptor(context, chuckCollector).maxContentLength(250000L), true) + addInterceptor(ChuckerInterceptor(context, chuckerCollector), true) } } @Singleton @Provides - fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector { - return ChuckCollector(context) - .showNotification(prefRepository.isDebugNotificationEnable) - .retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR)) + fun provideChuckerCollector(context: Context, prefRepository: PreferencesRepository): ChuckerCollector { + return ChuckerCollector( + context = context, + showNotification = prefRepository.isDebugNotificationEnable, + retentionPeriod = RetentionManager.Period.ONE_HOUR + ) } @Singleton diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt index ba10af6bf..34dc3418b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/ErrorHandler.kt @@ -1,7 +1,7 @@ package io.github.wulkanowy.ui.base import android.content.res.Resources -import com.readystatesoftware.chuck.api.ChuckCollector +import com.chuckerteam.chucker.api.ChuckerCollector import io.github.wulkanowy.R import io.github.wulkanowy.data.exceptions.NoCurrentStudentException import io.github.wulkanowy.sdk.exception.BadCredentialsException @@ -15,7 +15,7 @@ import java.net.SocketTimeoutException import java.net.UnknownHostException import javax.inject.Inject -open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckCollector: ChuckCollector) { +open class ErrorHandler @Inject constructor(protected val resources: Resources, private val chuckerCollector: ChuckerCollector) { var showErrorMessage: (String, Throwable) -> Unit = { _, _ -> } @@ -24,7 +24,7 @@ open class ErrorHandler @Inject constructor(protected val resources: Resources, var onNoCurrentStudent: () -> Unit = {} fun dispatch(error: Throwable) { - chuckCollector.onError(error.javaClass.simpleName, error) + chuckerCollector.onError(error.javaClass.simpleName, error) Timber.e(error, "An exception occurred while the Wulkanowy was running") proceed(error) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt index 090fe6de9..5ed181bf1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/LoginErrorHandler.kt @@ -2,7 +2,7 @@ package io.github.wulkanowy.ui.modules.login import android.content.res.Resources import android.database.sqlite.SQLiteConstraintException -import com.readystatesoftware.chuck.api.ChuckCollector +import com.chuckerteam.chucker.api.ChuckerCollector import io.github.wulkanowy.R import io.github.wulkanowy.sdk.exception.BadCredentialsException import io.github.wulkanowy.sdk.mobile.exception.InvalidPinException @@ -14,8 +14,8 @@ import javax.inject.Inject class LoginErrorHandler @Inject constructor( resources: Resources, - chuckCollector: ChuckCollector -) : ErrorHandler(resources, chuckCollector) { + chuckerCollector: ChuckerCollector +) : ErrorHandler(resources, chuckerCollector) { var onBadCredentials: () -> Unit = {} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt index ef81c410b..110dd82e5 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/RecoverErrorHandler.kt @@ -1,7 +1,7 @@ package io.github.wulkanowy.ui.modules.login.recover import android.content.res.Resources -import com.readystatesoftware.chuck.api.ChuckCollector +import com.chuckerteam.chucker.api.ChuckerCollector import io.github.wulkanowy.sdk.scrapper.exception.InvalidCaptchaException import io.github.wulkanowy.sdk.scrapper.exception.InvalidEmailException import io.github.wulkanowy.sdk.scrapper.exception.NoAccountFoundException @@ -10,8 +10,8 @@ import javax.inject.Inject class RecoverErrorHandler @Inject constructor( resources: Resources, - chuckCollector: ChuckCollector -) : ErrorHandler(resources, chuckCollector) { + chuckerCollector: ChuckerCollector +) : ErrorHandler(resources, chuckerCollector) { var onInvalidUsername: (String) -> Unit = {} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index 89ba0ee5e..3f2bf714c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -1,6 +1,6 @@ package io.github.wulkanowy.ui.modules.settings -import com.readystatesoftware.chuck.api.ChuckCollector +import com.chuckerteam.chucker.api.ChuckerCollector import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.services.sync.SyncManager @@ -21,7 +21,7 @@ class SettingsPresenter @Inject constructor( private val preferencesRepository: PreferencesRepository, private val analytics: FirebaseAnalyticsHelper, private val syncManager: SyncManager, - private val chuckCollector: ChuckCollector, + private val chuckerCollector: ChuckerCollector, private val appInfo: AppInfo ) : BasePresenter(errorHandler, studentRepository, schedulers) { @@ -38,7 +38,7 @@ class SettingsPresenter @Inject constructor( when (key) { serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() } servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true) - isDebugNotificationEnableKey -> chuckCollector.showNotification(isDebugNotificationEnable) + isDebugNotificationEnableKey -> chuckerCollector.showNotification = isDebugNotificationEnable appThemeKey -> view?.recreateView() appLanguageKey -> view?.run { updateLanguage(if (appLanguage == "system") appInfo.systemLanguage else appLanguage) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt index 1d043af3a..c1389cedd 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsErrorHandler.kt @@ -1,15 +1,15 @@ package io.github.wulkanowy.ui.modules.timetable.completed import android.content.res.Resources -import com.readystatesoftware.chuck.api.ChuckCollector +import com.chuckerteam.chucker.api.ChuckerCollector import io.github.wulkanowy.sdk.exception.FeatureDisabledException import io.github.wulkanowy.ui.base.ErrorHandler import javax.inject.Inject class CompletedLessonsErrorHandler @Inject constructor( resources: Resources, - chuckCollector: ChuckCollector -) : ErrorHandler(resources, chuckCollector) { + chuckerCollector: ChuckerCollector +) : ErrorHandler(resources, chuckerCollector) { var onFeatureDisabled: () -> Unit = {} From 2137b6c225d84e54efc0202ad19da65ef79695fc Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 28 Mar 2020 10:56:07 +0000 Subject: [PATCH 15/61] Bump threetenabp from 1.2.2 to 1.2.3 (#735) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ef9cf8e64..136481f3e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -171,7 +171,7 @@ dependencies { implementation "io.reactivex.rxjava2:rxjava:2.2.19" implementation "com.google.code.gson:gson:2.8.6" - implementation "com.jakewharton.threetenabp:threetenabp:1.2.2" + implementation "com.jakewharton.threetenabp:threetenabp:1.2.3" implementation "com.jakewharton.timber:timber:4.7.1" implementation "at.favre.lib:slf4j-timber:1.0.1" implementation "fr.bipi.treessence:treessence:0.3.2" From d9c8bb399bcffab3ff037d348dde1a7278e3365d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stanis=C5=82aw=20Jelnicki?= <25802745+JelNiSlaw@users.noreply.github.com> Date: Sat, 28 Mar 2020 19:51:22 +0100 Subject: [PATCH 16/61] Change strings.xml form from male to impersonal (#736) --- app/src/main/res/values-pl/strings.xml | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 041a65785..6877330fc 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -117,10 +117,10 @@ Nowe oceny - Dostałeś %1$d ocenę - "Dostałeś %1$d oceny - Dostałeś %1$d ocen - Dostałeś %1$d ocen + Masz %1$d nową ocenę + Masz %1$d nowe oceny + Masz %1$d nowych ocen + Masz %1$d nowych ocen @@ -144,13 +144,13 @@ Podsumowanie frekwencji - Nieobecny z przyczyn szkolnych + Nieobecność z przyczyn szkolnych Nieobecność usprawiedliwiona Nieobecność nieusprawiedliwiona - Zwolniony + Zwolnienie Spóźnienie usprawiedliwione Spóźnienie nieusprawiedliwione - Obecny + Obecność Numer lekcji Brak wpisów @@ -211,10 +211,10 @@ Nowe wiadomości - Dostałeś %1$d wiadomość - "Dostałeś %1$d wiadomości - Dostałeś %1$d wiadomości - Dostałeś %1$d wiadomości + Masz %1$d nową wiadomość + Masz %1$d nowe wiadomości + Masz %1$d nowych wiadomości + Masz %1$d nowych wiadomości @@ -233,10 +233,10 @@ Nowe uwagi - Dostałeś %1$d uwagę - "Dostałeś %1$d uwagi - Dostałeś %1$d uwag - Dostałeś %1$d uwag + Masz %1$d nową uwagę + Masz %1$d nowe uwagi + Masz %1$d nowych uwag + Masz %1$d nowych uwag From 6f697eff47eb6704cd3cda22b17800a296f1714f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 29 Mar 2020 14:26:56 +0200 Subject: [PATCH 17/61] Add points to notes (#738) --- app/build.gradle | 2 +- .../23.json | 1682 +++++++++++++++++ .../github/wulkanowy/data/db/AppDatabase.kt | 6 +- .../github/wulkanowy/data/db/entities/Note.kt | 11 + .../data/db/migrations/Migration23.kt | 14 + .../data/repositories/note/NoteRemote.kt | 4 + .../wulkanowy/ui/modules/note/NoteDialog.kt | 15 + .../wulkanowy/ui/modules/note/NoteItem.kt | 29 +- app/src/main/res/layout/dialog_note.xml | 16 + app/src/main/res/layout/item_note.xml | 69 +- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values/colors.xml | 3 + app/src/main/res/values/strings.xml | 1 + 16 files changed, 1824 insertions(+), 32 deletions(-) create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration23.kt diff --git a/app/build.gradle b/app/build.gradle index 136481f3e..ab90d6001 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -123,7 +123,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:be7ed9c" + implementation "io.github.wulkanowy:sdk:4ea879b" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json new file mode 100644 index 000000000..f75a72acf --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/23.json @@ -0,0 +1,1682 @@ +{ + "formatVersion": 1, + "database": { + "version": 23, + "identityHash": "f2505bf0c76c3ae4567856536d790909", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scrapperBaseUrl", + "columnName": "scrapper_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobileBaseUrl", + "columnName": "mobile_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "login_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginMode", + "columnName": "login_mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "certificateKey", + "columnName": "certificate_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateKey", + "columnName": "private_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isParent", + "columnName": "is_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "user_login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolShortName", + "columnName": "school_short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "current", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isStudentPlan", + "columnName": "student_plan", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timeId", + "columnName": "time_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excusable", + "columnName": "excusable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excuseStatus", + "columnName": "excuse_status", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `grade` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `is_semester` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "grade", + "columnName": "grade", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "is_semester", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesPointsStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "others", + "columnName": "others", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "student", + "columnName": "student", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `removed` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "categoryType", + "columnName": "category_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPointsShow", + "columnName": "is_points_show", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "School", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contact", + "columnName": "contact", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "headmaster", + "columnName": "headmaster", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pedagogue", + "columnName": "pedagogue", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f2505bf0c76c3ae4567856536d790909')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index 4eaf89e59..adfb18310 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -63,6 +63,7 @@ import io.github.wulkanowy.data.db.migrations.Migration2 import io.github.wulkanowy.data.db.migrations.Migration20 import io.github.wulkanowy.data.db.migrations.Migration21 import io.github.wulkanowy.data.db.migrations.Migration22 +import io.github.wulkanowy.data.db.migrations.Migration23 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration5 @@ -104,7 +105,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 22 + const val VERSION_SCHEMA = 23 fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array { return arrayOf( @@ -128,7 +129,8 @@ abstract class AppDatabase : RoomDatabase() { Migration19(sharedPrefProvider), Migration20(), Migration21(), - Migration22() + Migration22(), + Migration23() ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt index 5f3a92ab6..6f707a66a 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Note.kt @@ -16,8 +16,19 @@ data class Note( val teacher: String, + @ColumnInfo(name = "teacher_symbol") + val teacherSymbol: String, + val category: String, + @ColumnInfo(name = "category_type") + val categoryType: Int, + + @ColumnInfo(name = "is_points_show") + val isPointsShow: Boolean, + + val points: Int, + val content: String ) : Serializable { diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration23.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration23.kt new file mode 100644 index 000000000..22de94c3f --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration23.kt @@ -0,0 +1,14 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration23 : Migration(22, 23) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''") + database.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0") + database.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0") + database.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0") + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt index 503575b69..cd78abd3c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt @@ -18,7 +18,11 @@ class NoteRemote @Inject constructor(private val sdk: Sdk) { studentId = semester.studentId, date = it.date, teacher = it.teacher, + teacherSymbol = it.teacherSymbol, category = it.category, + categoryType = it.categoryType.id, + isPointsShow = it.showPoints, + points = it.points, content = it.content ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt index 492aeab26..20ffea4eb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteDialog.kt @@ -1,14 +1,18 @@ package io.github.wulkanowy.ui.modules.note +import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Note +import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.toFormattedString import kotlinx.android.synthetic.main.dialog_note.* +import io.github.wulkanowy.sdk.scrapper.notes.Note.CategoryType class NoteDialog : DialogFragment() { @@ -36,6 +40,7 @@ class NoteDialog : DialogFragment() { return inflater.inflate(R.layout.dialog_note, container, false) } + @SuppressLint("SetTextI18n") override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) @@ -43,6 +48,16 @@ class NoteDialog : DialogFragment() { noteDialogCategory.text = note.category noteDialogTeacher.text = note.teacher noteDialogContent.text = note.content + if (note.isPointsShow) { + with(noteDialogPoints) { + text = "${if (note.points > 0) "+" else ""}${note.points}" + setTextColor(when (CategoryType.getByValue(note.categoryType)) { + CategoryType.POSITIVE -> ContextCompat.getColor(requireContext(), R.color.note_positive) + CategoryType.NEGATIVE -> ContextCompat.getColor(requireContext(), R.color.note_negative) + else -> requireContext().getThemeAttrColor(android.R.attr.textColorPrimary) + }) + } + } noteDialogClose.setOnClickListener { dismiss() } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt index dabeef74a..53fe6fa91 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/note/NoteItem.kt @@ -1,14 +1,20 @@ package io.github.wulkanowy.ui.modules.note +import android.annotation.SuppressLint import android.graphics.Typeface.BOLD import android.graphics.Typeface.NORMAL import android.view.View +import android.view.View.GONE +import android.view.View.VISIBLE +import androidx.core.content.ContextCompat import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.viewholders.FlexibleViewHolder import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Note +import io.github.wulkanowy.sdk.scrapper.notes.Note.CategoryType +import io.github.wulkanowy.utils.getThemeAttrColor import io.github.wulkanowy.utils.toFormattedString import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.item_note.* @@ -17,20 +23,30 @@ class NoteItem(val note: Note) : AbstractFlexibleItem() { override fun getLayoutRes() = R.layout.item_note - override fun createViewHolder(view: View, adapter: FlexibleAdapter>): NoteItem.ViewHolder { - return NoteItem.ViewHolder(view, adapter) + override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ViewHolder { + return ViewHolder(view, adapter) } - override fun bindViewHolder(adapter: FlexibleAdapter>, holder: NoteItem.ViewHolder, position: Int, payloads: MutableList?) { + @SuppressLint("SetTextI18n") + override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ViewHolder, position: Int, payloads: MutableList?) { holder.apply { - noteItemDate.apply { + with(noteItemDate) { text = note.date.toFormattedString() setTypeface(null, if (note.isRead) NORMAL else BOLD) } - noteItemType.apply { + with(noteItemType) { text = note.category setTypeface(null, if (note.isRead) NORMAL else BOLD) } + with(noteItemPoints) { + text = "${if (note.points > 0) "+" else ""}${note.points}" + visibility = if (note.isPointsShow) VISIBLE else GONE + setTextColor(when(CategoryType.getByValue(note.categoryType)) { + CategoryType.POSITIVE -> ContextCompat.getColor(context, R.color.note_positive) + CategoryType.NEGATIVE -> ContextCompat.getColor(context, R.color.note_negative) + else -> context.getThemeAttrColor(android.R.attr.textColorPrimary) + }) + } noteItemTeacher.text = note.teacher noteItemContent.text = note.content } @@ -53,7 +69,8 @@ class NoteItem(val note: Note) : AbstractFlexibleItem() { return result } - class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer { + class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : + FlexibleViewHolder(view, adapter), LayoutContainer { override val containerView: View get() = contentView } diff --git a/app/src/main/res/layout/dialog_note.xml b/app/src/main/res/layout/dialog_note.xml index 0393e56af..71506b01f 100644 --- a/app/src/main/res/layout/dialog_note.xml +++ b/app/src/main/res/layout/dialog_note.xml @@ -64,6 +64,22 @@ android:textIsSelectable="true" android:textSize="12sp" /> + + + + + + - + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 8a75d5c85..5859a3630 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -201,6 +201,7 @@ Keine Informationen über Eintragen + Punkte %d Eintrag %d Eintragen diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 6877330fc..5ebaf2536 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -220,6 +220,7 @@ Brak informacji o uwagach + Punkty %d uwaga %d uwagi diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 6134d755a..93f986041 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -216,6 +216,7 @@ Нет данных о предупреждениях + точек %d предупреждение %d предупреждения diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 9b43f4a2c..eecb286b8 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -217,6 +217,7 @@ Немає даних про нотатки + точок %d нотатка %d нотатки diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 6221ef99b..36dee1812 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -12,6 +12,9 @@ #1f000000 #1fffffff + #a0c431 + #d43f3f + #424242 #d43f3f #49a6f2 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1e98ba946..243fc0be7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -209,6 +209,7 @@ No info about notes + Points %d note %d notes From b9a19b60e4f76c20cb109379dc5ff3df76f12783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 29 Mar 2020 14:38:39 +0200 Subject: [PATCH 18/61] =?UTF-8?q?Bump=20appcompat=20from=201.1.0=20to=201.?= =?UTF-8?q?2.0-alpha03=20to=20fix=20webview=20crash=E2=80=A6=20(#737)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ab90d6001..a419f7dec 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,7 +128,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.activity:activity-ktx:1.1.0" - implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.appcompat:appcompat:1.2.0-alpha03" implementation "androidx.appcompat:appcompat-resources:1.1.0" implementation "androidx.fragment:fragment-ktx:1.2.3" implementation "androidx.annotation:annotation:1.1.0" From d9322b0df4dd0b0f5a309f4510a11439f490c826 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 29 Mar 2020 18:55:00 +0200 Subject: [PATCH 19/61] Bump aboutlibraries-core from 7.1.0 to 8.0.0 (#731) --- app/build.gradle | 7 ++++++- app/proguard-rules.pro | 7 +++++++ .../ui/modules/about/license/LicenseItem.kt | 2 +- .../modules/about/license/LicensePresenter.kt | 4 ---- app/src/main/res/layout/item_license.xml | 4 +++- .../main/res/raw/custom_license_mappings.prop | 1 + .../res/raw/custom_license_year_mappings.prop | 3 +++ app/src/main/res/raw/custom_name_mappings.prop | 3 +++ .../main/res/values/library_wulkanowy_api.xml | 17 ----------------- build.gradle | 2 ++ 10 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 app/src/main/res/raw/custom_license_mappings.prop create mode 100644 app/src/main/res/raw/custom_license_year_mappings.prop create mode 100644 app/src/main/res/raw/custom_name_mappings.prop delete mode 100644 app/src/main/res/values/library_wulkanowy_api.xml diff --git a/app/build.gradle b/app/build.gradle index a419f7dec..c257979f0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,7 @@ apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' apply plugin: 'io.fabric' apply plugin: 'com.github.triplet.play' +apply plugin: 'com.mikepenz.aboutlibraries.plugin' apply from: 'jacoco.gradle' apply from: 'sonarqube.gradle' apply from: 'hooks.gradle' @@ -96,6 +97,10 @@ android { exclude 'META-INF/library_release.kotlin_module' exclude 'META-INF/library-core_release.kotlin_module' } + + aboutLibraries { + configPath = "app/src/main/res/raw" + } } androidExtensions { @@ -175,7 +180,7 @@ dependencies { implementation "com.jakewharton.timber:timber:4.7.1" implementation "at.favre.lib:slf4j-timber:1.0.1" implementation "fr.bipi.treessence:treessence:0.3.2" - implementation "com.mikepenz:aboutlibraries-core:7.1.0" + implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation 'com.wdullaer:materialdatetimepicker:4.2.3' implementation("io.coil-kt:coil:0.9.5") diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 77339fe9e..1a8b8c329 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -43,3 +43,10 @@ #Config for Material Components -keep class com.google.android.material.tabs.** { *; } + + +#Config for About Libraries +-keep class .R +-keep class **.R$* { + ; +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicenseItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicenseItem.kt index 98c86e75a..8dcb89224 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicenseItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicenseItem.kt @@ -19,7 +19,7 @@ class LicenseItem(val library: Library) : AbstractFlexibleItem>, holder: ViewHolder, position: Int, payloads: MutableList) { with(holder) { licenseItemName.text = library.libraryName - licenseItemSummary.text = library.license?.licenseName + licenseItemSummary.text = library.license?.licenseName?.takeIf { it.isNotBlank() } ?: library.libraryVersion } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicensePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicensePresenter.kt index b5b8fcd13..dc48b098b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicensePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/license/LicensePresenter.kt @@ -27,10 +27,6 @@ class LicensePresenter @Inject constructor( private fun loadData() { disposable.add(Single.fromCallable { view?.appLibraries } - .map { - val exclude = listOf("Android-Iconics", "CircleImageView", "FastAdapter", "Jsoup", "okio", "Retrofit") - it.filter { library -> !exclude.contains(library.libraryName) } - } .map { it.map { library -> LicenseItem(library) } } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) diff --git a/app/src/main/res/layout/item_license.xml b/app/src/main/res/layout/item_license.xml index 6a864433a..f44c211ca 100644 --- a/app/src/main/res/layout/item_license.xml +++ b/app/src/main/res/layout/item_license.xml @@ -14,9 +14,11 @@ android:id="@+id/licenseItemName" android:layout_width="match_parent" android:layout_height="28dp" + android:ellipsize="end" android:gravity="bottom" + android:singleLine="true" android:textSize="16sp" - tools:text="@tools:sample/lorem" /> + tools:text="@tools:sample/lorem/random" /> - - - - Wulkanowy - https://github.com/wulkanowy - - UONET+ Scraping API - The UONET+ client using web scraping - https://github.com/wulkanowy/api - Development - - true - https://github.com/wulkanowy/api - - apache_2_0 - diff --git a/build.gradle b/build.gradle index cc32f3163..3b77dee35 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ buildscript { ext.kotlin_version = '1.3.71' + ext.about_libraries = '8.0.2' repositories { mavenCentral() google() @@ -16,6 +17,7 @@ buildscript { classpath "com.github.triplet.gradle:play-publisher:2.7.2" classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0" + classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${about_libraries}" } } From 6440820dc5a634ace538debd5973dc1393fab835 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 18:56:41 +0000 Subject: [PATCH 20/61] Bump gradle from 3.6.1 to 3.6.2 (#744) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3b77dee35..1e62fc329 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ buildscript { } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.android.tools.build:gradle:3.6.1' + classpath 'com.android.tools.build:gradle:3.6.2' classpath 'com.google.gms:google-services:4.3.3' //noinspection GradleDependency https://github.com/firebase/firebase-android-sdk/issues/1276#issuecomment-592098283 classpath "io.fabric.tools:gradle:1.31.0" From 184c9413f8bafb7f658400c24eb6abce60de0519 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 18:58:26 +0000 Subject: [PATCH 21/61] Bump firebase-core from 17.2.3 to 17.3.0 (#746) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index c257979f0..26e530d99 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -185,7 +185,7 @@ dependencies { implementation("io.coil-kt:coil:0.9.5") - playImplementation "com.google.firebase:firebase-core:17.2.3" + playImplementation "com.google.firebase:firebase-core:17.3.0" playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1" releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" From a0587a8bce17cc7a39ff3d368ef6aaa59a519423 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 22:00:50 +0000 Subject: [PATCH 22/61] Bump fragment-ktx from 1.2.3 to 1.2.4 (#748) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 26e530d99..2dba69940 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -135,7 +135,7 @@ dependencies { implementation "androidx.activity:activity-ktx:1.1.0" implementation "androidx.appcompat:appcompat:1.2.0-alpha03" implementation "androidx.appcompat:appcompat-resources:1.1.0" - implementation "androidx.fragment:fragment-ktx:1.2.3" + implementation "androidx.fragment:fragment-ktx:1.2.4" implementation "androidx.annotation:annotation:1.1.0" implementation "androidx.multidex:multidex:2.0.1" From 6ec13c896de83e1dc22f483b9d602759da2a451a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 22:01:41 +0000 Subject: [PATCH 23/61] Bump about_libraries from 8.0.2 to 8.1.0 (#747) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1e62fc329..f8aea2550 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext.kotlin_version = '1.3.71' - ext.about_libraries = '8.0.2' + ext.about_libraries = '8.1.0' repositories { mavenCentral() google() From 0cb4866f4037ae474823da5bc1f95cb34e425422 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2020 22:21:25 +0000 Subject: [PATCH 24/61] Bump appcompat from 1.2.0-alpha03 to 1.2.0-beta01 (#749) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 2dba69940..df1f0822e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -133,7 +133,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" implementation "androidx.activity:activity-ktx:1.1.0" - implementation "androidx.appcompat:appcompat:1.2.0-alpha03" + implementation "androidx.appcompat:appcompat:1.2.0-beta01" implementation "androidx.appcompat:appcompat-resources:1.1.0" implementation "androidx.fragment:fragment-ktx:1.2.4" implementation "androidx.annotation:annotation:1.1.0" From 358c87528a0af20cf095ed5d4059b41a6443da37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Thu, 2 Apr 2020 00:34:24 +0200 Subject: [PATCH 25/61] Update gradle to 6.2.2 (#750) --- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 29 ++++++++++------------- gradlew.bat | 3 +++ 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index f8aea2550..47a365b6c 100644 --- a/build.gradle +++ b/build.gradle @@ -14,8 +14,8 @@ buildscript { classpath 'com.google.gms:google-services:4.3.3' //noinspection GradleDependency https://github.com/firebase/firebase-android-sdk/issues/1276#issuecomment-592098283 classpath "io.fabric.tools:gradle:1.31.0" - classpath "com.github.triplet.gradle:play-publisher:2.7.2" - classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8.0.1969" + classpath "com.github.triplet.gradle:play-publisher:2.7.3" + classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8" classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0" classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${about_libraries}" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..f3d88b1c2faf2fc91d853cd5d4242b5547257070 100644 GIT binary patch delta 22808 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 b$#%!p#R9xp*+AlE3}y_kgcumyFM)Uf(nCre delta 20005 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6254d2d4a..84a906615 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfdc..2fe81a7d9 100755 --- a/gradlew +++ b/gradlew @@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +175,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a141..9109989e3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" From c0adeaadfdaa8abc01ca16a3507ad4436ad40dab Mon Sep 17 00:00:00 2001 From: Mateusz Idziejczak <53345435+PanTajemnic@users.noreply.github.com> Date: Thu, 2 Apr 2020 20:26:28 +0200 Subject: [PATCH 26/61] Add "System theme" option to widgets (#739) --- .../LuckyNumberWidgetConfigureActivity.kt | 17 +++++++++++++---- .../TimetableWidgetConfigureActivity.kt | 13 +++++++++++-- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 7 files changed, 29 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt index e8ce3bcfb..056a15270 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt @@ -4,6 +4,9 @@ import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS import android.content.Intent +import android.content.res.Configuration +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import android.os.Build import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AlertDialog @@ -13,6 +16,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.login.LoginActivity +import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.activity_widget_configure.* import javax.inject.Inject @@ -26,6 +30,9 @@ class LuckyNumberWidgetConfigureActivity : BaseActivity= Build.VERSION_CODES.Q) items+=(getString(R.string.widget_timetable_theme_system)) - dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher) + dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher) .setTitle(R.string.widget_timetable_theme_title) - .setOnDismissListener { presenter.onDismissThemeView() } + .setOnDismissListener { presenter.onDismissThemeView() } .setSingleChoiceItems(items, -1) { _, which -> - presenter.onThemeSelect(which) + val isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES + presenter.onThemeSelect(if (isDarkMode && which == 2 || which == 1) 1 else 0) } .show() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt index 7636637f4..112092816 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt @@ -4,6 +4,9 @@ import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS import android.content.Intent +import android.content.res.Configuration +import android.content.res.Configuration.UI_MODE_NIGHT_YES +import android.os.Build import android.os.Bundle import android.widget.Toast import android.widget.Toast.LENGTH_LONG @@ -15,6 +18,7 @@ import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_PROVIDER +import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.activity_widget_configure.* import javax.inject.Inject @@ -28,6 +32,9 @@ class TimetableWidgetConfigureActivity : BaseActivity= Build.VERSION_CODES.Q) items += getString(R.string.widget_timetable_theme_system) dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher) .setTitle(R.string.widget_timetable_theme_title) .setOnDismissListener { presenter.onDismissThemeView() } .setSingleChoiceItems(items, -1) { _, which -> - presenter.onThemeSelect(which) + val isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES + presenter.onThemeSelect(if (isDarkMode && which == 2 || which == 1) 1 else 0) } .show() } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5859a3630..9d14bb560 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -322,6 +322,7 @@ Thema wählen Licht Dunkel + Systemthema diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 5ebaf2536..af35109fd 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -347,6 +347,7 @@ Wybierz motyw Jasny Ciemny + Motyw systemu diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 93f986041..5ff83d3e6 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -344,6 +344,7 @@ Выбрать тему Светлая Тёмная + Системная тема diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index eecb286b8..47b06ca37 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -345,6 +345,7 @@ Вибрати тему Світла Темна + Тема системи diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 243fc0be7..21ee8beda 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -330,6 +330,7 @@ Choose theme Light Dark + System Theme From da357775ffb7b4082b55b02a772340cf3ece5ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 2 Apr 2020 20:27:14 +0200 Subject: [PATCH 27/61] Add better validation to login/email field (#741) --- .../login/advanced/LoginAdvancedFragment.kt | 14 ++++++++++ .../login/advanced/LoginAdvancedPresenter.kt | 28 ++++++++----------- .../login/advanced/LoginAdvancedView.kt | 4 +++ .../modules/login/form/LoginFormFragment.kt | 14 ++++++++++ .../modules/login/form/LoginFormPresenter.kt | 10 +++++++ .../ui/modules/login/form/LoginFormView.kt | 4 +++ app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../login/form/LoginFormPresenterTest.kt | 16 +++++------ 12 files changed, 71 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt index 99090902b..aaea31eca 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedFragment.kt @@ -146,6 +146,20 @@ class LoginAdvancedFragment : BaseFragment(), LoginAdvancedView { } } + override fun setErrorLoginRequired() { + with(loginFormUsernameLayout) { + requestFocus() + error = getString(R.string.login_invalid_login) + } + } + + override fun setErrorEmailRequired() { + with(loginFormUsernameLayout) { + requestFocus() + error = getString(R.string.login_invalid_email) + } + } + override fun setErrorPassRequired(focus: Boolean) { with(loginFormPassLayout) { if (focus) requestFocus() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt index 212f7b679..3a0d4a0d8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedPresenter.kt @@ -173,6 +173,8 @@ class LoginAdvancedPresenter @Inject constructor( val login = view?.formUsernameValue.orEmpty() val password = view?.formPassValue.orEmpty() + val host = view?.formHostValue.orEmpty() + val pin = view?.formPinValue.orEmpty() val symbol = view?.formSymbolValue.orEmpty() val token = view?.formTokenValue.orEmpty() @@ -196,26 +198,20 @@ class LoginAdvancedPresenter @Inject constructor( isCorrect = false } } - Sdk.Mode.SCRAPPER -> { + Sdk.Mode.HYBRID, Sdk.Mode.SCRAPPER -> { if (login.isEmpty()) { view?.setErrorUsernameRequired() isCorrect = false - } + } else { + if ("@" in login && "standard" !in host) { + view?.setErrorLoginRequired() + isCorrect = false + } - if (password.isEmpty()) { - view?.setErrorPassRequired(focus = isCorrect) - isCorrect = false - } - - if (password.length < 6 && password.isNotEmpty()) { - view?.setErrorPassInvalid(focus = isCorrect) - isCorrect = false - } - } - Sdk.Mode.HYBRID -> { - if (login.isEmpty()) { - view?.setErrorUsernameRequired() - isCorrect = false + if ("@" !in login && "standard" in host) { + view?.setErrorEmailRequired() + isCorrect = false + } } if (password.isEmpty()) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt index eb280235b..36c9a93f8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/advanced/LoginAdvancedView.kt @@ -41,6 +41,10 @@ interface LoginAdvancedView : BaseView { fun setErrorUsernameRequired() + fun setErrorLoginRequired() + + fun setErrorEmailRequired() + fun setErrorPassRequired(focus: Boolean) fun setErrorPassInvalid(focus: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index 67e8a740a..b79da3cca 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -121,6 +121,20 @@ class LoginFormFragment : BaseFragment(), LoginFormView { } } + override fun setErrorLoginRequired() { + with(loginFormUsernameLayout) { + requestFocus() + error = getString(R.string.login_invalid_login) + } + } + + override fun setErrorEmailRequired() { + with(loginFormUsernameLayout) { + requestFocus() + error = getString(R.string.login_invalid_email) + } + } + override fun setErrorSymbolRequired(focus: Boolean) { with(loginFormSymbolLayout) { if (focus) requestFocus() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index 6d4292856..3ed40539d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -131,6 +131,16 @@ class LoginFormPresenter @Inject constructor( if (login.isEmpty()) { view?.setErrorUsernameRequired() isCorrect = false + } else { + if ("@" in login && "standard" !in host) { + view?.setErrorLoginRequired() + isCorrect = false + } + + if ("@" !in login && "standard" in host) { + view?.setErrorEmailRequired() + isCorrect = false + } } if (password.isEmpty()) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt index 4a570f5cf..80cf58448 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt @@ -31,6 +31,10 @@ interface LoginFormView : BaseView { fun setErrorUsernameRequired() + fun setErrorLoginRequired() + + fun setErrorEmailRequired() + fun setErrorSymbolRequired(focus: Boolean) fun setErrorPassRequired(focus: Boolean) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9d14bb560..87c906542 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -48,6 +48,7 @@ Ungültige token Token ist nicht mehr gültig Ungültige email + Ungültige login Ungültige symbol Student nicht gefunden. Überprüfen Sie das Symbol Dieses Datenfeld ist erforderlich diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index af35109fd..c80137b1e 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -49,6 +49,7 @@ Nieprawidłowy token Token stracił ważność Niepoprawny adres email + Niepoprawny login Niepoprawny symbol Nie znaleziono ucznia. Sprawdź symbol To pole jest wymagane diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 5ff83d3e6..e5530400f 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -49,6 +49,7 @@ Недействительный token Токен просрочен Неверный адрес электронной почты + Неправильный логин Недействительный symbol Не удалось найти ученика. Пожалуйста, проверьте \"symbol\" Это поле обязательно diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 47b06ca37..cd1c3b5d0 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -49,6 +49,7 @@ Недійсний PIN Недійсний token Недійсна адреса електронної пошти + Невірний логін Токен протермінований Недійсний symbol Не вдалося знайти учня. Будь ласка, перевірте \"symbol\" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 21ee8beda..30cc086de 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,6 +50,7 @@ Invalid token Token expired Invalid email + Invalid login Invalid symbol Student not found. Check the symbol This field is required diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt index 05b543f10..779a605fc 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenterTest.kt @@ -52,7 +52,7 @@ class LoginFormPresenterTest { fun emptyNicknameLoginTest() { `when`(loginFormView.formUsernameValue).thenReturn("") `when`(loginFormView.formPassValue).thenReturn("test123") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") presenter.onSignInClick() verify(loginFormView).setErrorUsernameRequired() @@ -64,7 +64,7 @@ class LoginFormPresenterTest { fun emptyPassLoginTest() { `when`(loginFormView.formUsernameValue).thenReturn("@") `when`(loginFormView.formPassValue).thenReturn("") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") presenter.onSignInClick() verify(loginFormView, never()).setErrorUsernameRequired() @@ -76,7 +76,7 @@ class LoginFormPresenterTest { fun invalidPassLoginTest() { `when`(loginFormView.formUsernameValue).thenReturn("@") `when`(loginFormView.formPassValue).thenReturn("123") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") presenter.onSignInClick() verify(loginFormView, never()).setErrorUsernameRequired() @@ -86,12 +86,12 @@ class LoginFormPresenterTest { @Test fun loginTest() { - val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, schoolShortName = "", isParent = false) + val studentTest = Student(email = "test@", password = "123", scrapperBaseUrl = "https://fakelog.cf/", loginType = "AUTO", studentName = "", schoolSymbol = "", schoolName = "", studentId = 0, classId = 1, isCurrent = false, symbol = "", registrationDate = now(), className = "", mobileBaseUrl = "", privateKey = "", certificateKey = "", loginMode = "", userLoginId = 0, schoolShortName = "", isParent = false) doReturn(Single.just(listOf(studentTest))).`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString()) `when`(loginFormView.formUsernameValue).thenReturn("@") `when`(loginFormView.formPassValue).thenReturn("123456") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") `when`(loginFormView.formSymbolValue).thenReturn("Default") `when`(loginFormView.formHostSymbol).thenReturn("Default") presenter.onSignInClick() @@ -109,7 +109,7 @@ class LoginFormPresenterTest { .`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString()) `when`(loginFormView.formUsernameValue).thenReturn("@") `when`(loginFormView.formPassValue).thenReturn("123456") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") `when`(loginFormView.formSymbolValue).thenReturn("Default") `when`(loginFormView.formHostSymbol).thenReturn("Default") presenter.onSignInClick() @@ -127,7 +127,7 @@ class LoginFormPresenterTest { .`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString()) `when`(loginFormView.formUsernameValue).thenReturn("@") `when`(loginFormView.formPassValue).thenReturn("123456") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") `when`(loginFormView.formSymbolValue).thenReturn("Default") `when`(loginFormView.formHostSymbol).thenReturn("Default") presenter.onSignInClick() @@ -146,7 +146,7 @@ class LoginFormPresenterTest { doReturn(Single.error>(testException)).`when`(repository).getStudentsScrapper(anyString(), anyString(), anyString(), anyString()) `when`(loginFormView.formUsernameValue).thenReturn("@") `when`(loginFormView.formPassValue).thenReturn("123456") - `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf") + `when`(loginFormView.formHostValue).thenReturn("https://fakelog.cf/?standard") `when`(loginFormView.formSymbolValue).thenReturn("Default") `when`(loginFormView.formHostSymbol).thenReturn("Default") presenter.onSignInClick() From 502a98b70a4e64ecd41c417c68a4726a99c8db88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 2 Apr 2020 20:27:53 +0200 Subject: [PATCH 28/61] Add message attachments (#734) --- app/build.gradle | 2 +- .../24.json | 1732 +++++++++++++++++ .../github/wulkanowy/data/RepositoryModule.kt | 4 + .../github/wulkanowy/data/db/AppDatabase.kt | 11 +- .../data/db/dao/MessageAttachmentDao.kt | 13 + .../wulkanowy/data/db/dao/MessagesDao.kt | 9 +- .../wulkanowy/data/db/entities/Message.kt | 5 +- .../data/db/entities/MessageAttachment.kt | 26 + .../data/db/entities/MessageWithAttachment.kt | 12 + .../data/db/migrations/Migration24.kt | 21 + .../data/repositories/message/MessageLocal.kt | 16 +- .../repositories/message/MessageRemote.kt | 18 +- .../repositories/message/MessageRepository.kt | 25 +- .../ui/modules/message/MessageItem.kt | 6 +- .../message/preview/MessagePreviewAdapter.kt | 88 + .../message/preview/MessagePreviewFragment.kt | 49 +- .../preview/MessagePreviewPresenter.kt | 44 +- .../message/preview/MessagePreviewView.kt | 13 +- .../modules/message/tab/MessageTabFragment.kt | 5 +- .../message/tab/MessageTabPresenter.kt | 2 +- .../ui/modules/message/tab/MessageTabView.kt | 3 +- app/src/main/res/drawable/ic_attachment.xml | 9 + .../res/layout/fragment_message_preview.xml | 54 +- app/src/main/res/layout/item_message.xml | 52 +- .../res/layout/item_message_attachment.xml | 22 + .../main/res/layout/item_message_divider.xml | 6 + .../main/res/layout/item_message_preview.xml | 45 + .../message/MessageRepositoryTest.kt | 54 +- 28 files changed, 2157 insertions(+), 189 deletions(-) create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/MessageAttachmentDao.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration24.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt create mode 100644 app/src/main/res/drawable/ic_attachment.xml create mode 100644 app/src/main/res/layout/item_message_attachment.xml create mode 100644 app/src/main/res/layout/item_message_divider.xml create mode 100644 app/src/main/res/layout/item_message_preview.xml diff --git a/app/build.gradle b/app/build.gradle index df1f0822e..4a9755179 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,7 +128,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:4ea879b" + implementation "io.github.wulkanowy:sdk:44725a9" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json new file mode 100644 index 000000000..17ae7d798 --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/24.json @@ -0,0 +1,1732 @@ +{ + "formatVersion": 1, + "database": { + "version": 24, + "identityHash": "9bbf60310b56a855839164e2aae031f9", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scrapperBaseUrl", + "columnName": "scrapper_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobileBaseUrl", + "columnName": "mobile_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "login_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginMode", + "columnName": "login_mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "certificateKey", + "columnName": "certificate_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateKey", + "columnName": "private_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isParent", + "columnName": "is_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "user_login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolShortName", + "columnName": "school_short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "current", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isStudentPlan", + "columnName": "student_plan", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timeId", + "columnName": "time_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excusable", + "columnName": "excusable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excuseStatus", + "columnName": "excuse_status", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `grade` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `is_semester` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "grade", + "columnName": "grade", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "is_semester", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesPointsStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "others", + "columnName": "others", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "student", + "columnName": "student", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasAttachments", + "columnName": "has_attachments", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MessageAttachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))", + "fields": [ + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "oneDriveId", + "columnName": "one_drive_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filename", + "columnName": "filename", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "real_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "categoryType", + "columnName": "category_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPointsShow", + "columnName": "is_points_show", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "School", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contact", + "columnName": "contact", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "headmaster", + "columnName": "headmaster", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pedagogue", + "columnName": "pedagogue", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9bbf60310b56a855839164e2aae031f9')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index cb2daf685..43c27c529 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -97,6 +97,10 @@ internal class RepositoryModule { @Provides fun provideMessagesDao(database: AppDatabase) = database.messagesDao + @Singleton + @Provides + fun provideMessageAttachmentsDao(database: AppDatabase) = database.messageAttachmentDao + @Singleton @Provides fun provideExamDao(database: AppDatabase) = database.examsDao diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index adfb18310..695c2d870 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -17,6 +17,7 @@ import io.github.wulkanowy.data.db.dao.GradeStatisticsDao import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.HomeworkDao import io.github.wulkanowy.data.db.dao.LuckyNumberDao +import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.dao.MobileDeviceDao import io.github.wulkanowy.data.db.dao.NoteDao @@ -39,6 +40,7 @@ import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageAttachment import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Recipient @@ -64,6 +66,7 @@ import io.github.wulkanowy.data.db.migrations.Migration20 import io.github.wulkanowy.data.db.migrations.Migration21 import io.github.wulkanowy.data.db.migrations.Migration22 import io.github.wulkanowy.data.db.migrations.Migration23 +import io.github.wulkanowy.data.db.migrations.Migration24 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration5 @@ -87,6 +90,7 @@ import javax.inject.Singleton GradeStatistics::class, GradePointsStatistics::class, Message::class, + MessageAttachment::class, Note::class, Homework::class, Subject::class, @@ -105,7 +109,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 23 + const val VERSION_SCHEMA = 24 fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array { return arrayOf( @@ -130,7 +134,8 @@ abstract class AppDatabase : RoomDatabase() { Migration20(), Migration21(), Migration22(), - Migration23() + Migration23(), + Migration24() ) } @@ -166,6 +171,8 @@ abstract class AppDatabase : RoomDatabase() { abstract val messagesDao: MessagesDao + abstract val messageAttachmentDao: MessageAttachmentDao + abstract val noteDao: NoteDao abstract val homeworkDao: HomeworkDao diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessageAttachmentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessageAttachmentDao.kt new file mode 100644 index 000000000..3c511a277 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessageAttachmentDao.kt @@ -0,0 +1,13 @@ +package io.github.wulkanowy.data.db.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import io.github.wulkanowy.data.db.entities.MessageAttachment + +@Dao +interface MessageAttachmentDao : BaseDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAttachments(items: List): List +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt index 40ba0fe71..7a69e2707 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/MessagesDao.kt @@ -2,19 +2,22 @@ package io.github.wulkanowy.data.db.dao import androidx.room.Dao import androidx.room.Query +import androidx.room.Transaction import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.reactivex.Maybe import io.reactivex.Single @Dao interface MessagesDao : BaseDao { + @Transaction + @Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId") + fun loadMessageWithAttachment(studentId: Int, messageId: Int): Single + @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> - @Query("SELECT * FROM Messages WHERE id = :id") - fun load(id: Long): Single - @Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC") fun loadDeleted(studentId: Int): Maybe> } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt index 93e254c3b..058298415 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Message.kt @@ -44,7 +44,10 @@ data class Message( @ColumnInfo(name = "read_by") val readBy: Int, - val removed: Boolean + val removed: Boolean, + + @ColumnInfo(name = "has_attachments") + val hasAttachments: Boolean ) : Serializable { @PrimaryKey(autoGenerate = true) diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt new file mode 100644 index 000000000..d1886e910 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageAttachment.kt @@ -0,0 +1,26 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import java.io.Serializable + +@Entity(tableName = "MessageAttachments") +data class MessageAttachment( + + @PrimaryKey + @ColumnInfo(name = "real_id") + val realId: Int, + + @ColumnInfo(name = "message_id") + val messageId: Int, + + @ColumnInfo(name = "one_drive_id") + val oneDriveId: String, + + @ColumnInfo(name = "url") + val url: String, + + @ColumnInfo(name = "filename") + val filename: String +) : Serializable diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt new file mode 100644 index 000000000..2e7af0f40 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/MessageWithAttachment.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.data.db.entities + +import androidx.room.Embedded +import androidx.room.Relation + +data class MessageWithAttachment( + @Embedded + val message: Message, + + @Relation(parentColumn = "message_id", entityColumn = "message_id") + val attachments: List +) diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration24.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration24.kt new file mode 100644 index 000000000..604ed4875 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration24.kt @@ -0,0 +1,21 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration24 : Migration(23, 24) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0") + database.execSQL(""" + CREATE TABLE IF NOT EXISTS MessageAttachments ( + real_id INTEGER NOT NULL, + message_id INTEGER NOT NULL, + one_drive_id TEXT NOT NULL, + url TEXT NOT NULL, + filename TEXT NOT NULL, + PRIMARY KEY(real_id) + ) + """) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt index 386391b4f..53cf0a983 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageLocal.kt @@ -1,7 +1,10 @@ package io.github.wulkanowy.data.repositories.message +import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageAttachment +import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.message.MessageFolder.TRASHED import io.reactivex.Maybe @@ -10,7 +13,10 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) { +class MessageLocal @Inject constructor( + private val messagesDb: MessagesDao, + private val messageAttachmentDao: MessageAttachmentDao +) { fun saveMessages(messages: List) { messagesDb.insertAll(messages) @@ -24,8 +30,12 @@ class MessageLocal @Inject constructor(private val messagesDb: MessagesDao) { messagesDb.deleteAll(messages) } - fun getMessage(id: Long): Single { - return messagesDb.load(id) + fun getMessageWithAttachment(student: Student, message: Message): Single { + return messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) + } + + fun saveMessageAttachments(attachments: List) { + messageAttachmentDao.insertAttachments(attachments) } fun getMessages(student: Student, folder: MessageFolder): Maybe> { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt index d27eb904d..488522109 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.data.repositories.message import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageAttachment import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student @@ -33,14 +34,25 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) { unread = it.unread ?: false, unreadBy = it.unreadBy ?: 0, readBy = it.readBy ?: 0, - removed = it.removed + removed = it.removed, + hasAttachments = it.hasAttachments ) } } } - fun getMessagesContent(message: Message, markAsRead: Boolean = false): Single { - return sdk.getMessageContent(message.messageId, message.folderId, markAsRead, message.realId) + fun getMessagesContentDetails(message: Message, markAsRead: Boolean = false): Single>> { + return sdk.getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details -> + details.content to details.attachments.map { + MessageAttachment( + realId = it.id, + messageId = it.messageId, + oneDriveId = it.oneDriveId, + url = it.url, + filename = it.filename + ) + } + } } fun sendMessage(subject: String, content: String, recipients: List): Single { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt index cf0de0d58..396d5f689 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student @@ -11,7 +12,6 @@ import io.github.wulkanowy.data.repositories.message.MessageFolder.RECEIVED import io.github.wulkanowy.sdk.pojo.SentMessage import io.github.wulkanowy.utils.uniqueSubtract import io.reactivex.Completable -import io.reactivex.Maybe import io.reactivex.Single import timber.log.Timber import java.net.UnknownHostException @@ -48,30 +48,31 @@ class MessageRepository @Inject constructor( } } - fun getMessage(student: Student, messageDbId: Long, markAsRead: Boolean = false): Single { + fun getMessage(student: Student, message: Message, markAsRead: Boolean = false): Single { return Single.just(sdkHelper.init(student)) .flatMap { _ -> - local.getMessage(messageDbId) + local.getMessageWithAttachment(student, message) .filter { - it.content.isNotEmpty().also { status -> + it.message.content.isNotEmpty().also { status -> Timber.d("Message content in db empty: ${!status}") - } && !it.unread + } && !it.message.unread } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) local.getMessage(messageDbId) + if (it) local.getMessageWithAttachment(student, message) else Single.error(UnknownHostException()) } .flatMap { dbMessage -> - remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess { - local.updateMessages(listOf(dbMessage.copy(unread = !markAsRead).apply { - id = dbMessage.id - content = content.ifBlank { it } + remote.getMessagesContentDetails(dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) -> + local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply { + id = dbMessage.message.id + content = content.ifBlank { downloadedMessage } })) - Timber.d("Message $messageDbId with blank content: ${dbMessage.content.isBlank()}, marked as read") + local.saveMessageAttachments(attachments) + Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read") } }.flatMap { - local.getMessage(messageDbId) + local.getMessageWithAttachment(student, message) } ) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt index 19d6ad1de..7e52233c9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/MessageItem.kt @@ -39,6 +39,9 @@ class MessageItem(val message: Message, private val noSubjectString: String) : text = message.date.toFormattedString() setTypeface(null, style) } + with(messageItemAttachmentIcon) { + visibility = if (message.hasAttachments) View.VISIBLE else View.GONE + } } } @@ -56,7 +59,8 @@ class MessageItem(val message: Message, private val noSubjectString: String) : return message.hashCode() } - class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer { + class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : + FlexibleViewHolder(view, adapter), LayoutContainer { override val containerView: View get() = contentView } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt new file mode 100644 index 000000000..a0ac6ec70 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewAdapter.kt @@ -0,0 +1,88 @@ +package io.github.wulkanowy.ui.modules.message.preview + +import android.annotation.SuppressLint +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageAttachment +import io.github.wulkanowy.data.db.entities.MessageWithAttachment +import io.github.wulkanowy.data.repositories.message.MessageFolder +import io.github.wulkanowy.utils.openInternetBrowser +import io.github.wulkanowy.utils.toFormattedString +import kotlinx.android.synthetic.main.item_message_attachment.view.* +import kotlinx.android.synthetic.main.item_message_preview.view.* +import javax.inject.Inject + +class MessagePreviewAdapter @Inject constructor() : + RecyclerView.Adapter() { + + enum class ViewType(val id: Int) { + MESSAGE(1), + DIVIDER(2), + ATTACHMENT(3) + } + + var messageWithAttachment: MessageWithAttachment? = null + set(value) { + field = value + attachments = value?.attachments.orEmpty() + } + + private var attachments: List = emptyList() + + override fun getItemCount() = if (messageWithAttachment == null) 0 else attachments.size + 1 + if (attachments.isNotEmpty()) 1 else 0 + + override fun getItemViewType(position: Int) = when (position) { + 0 -> ViewType.MESSAGE.id + 1 -> ViewType.DIVIDER.id + else -> ViewType.ATTACHMENT.id + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + + return when (viewType) { + ViewType.MESSAGE.id -> MessageViewHolder(inflater.inflate(R.layout.item_message_preview, parent, false)) + ViewType.DIVIDER.id -> DividerViewHolder(inflater.inflate(R.layout.item_message_divider, parent, false)) + ViewType.ATTACHMENT.id -> AttachmentViewHolder(inflater.inflate(R.layout.item_message_attachment, parent, false)) + else -> throw IllegalStateException() + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is MessageViewHolder -> bindMessage(holder.view, requireNotNull(messageWithAttachment).message) + is AttachmentViewHolder -> bindAttachment(holder.view, requireNotNull(messageWithAttachment).attachments[position - 2]) + } + } + + @SuppressLint("SetTextI18n") + private fun bindMessage(view: View, message: Message) { + with(view) { + messagePreviewSubject.text = if (message.subject.isNotBlank()) message.subject else context.getString(R.string.message_no_subject) + messagePreviewDate.text = context.getString(R.string.message_date, message.date.toFormattedString("yyyy-MM-dd HH:mm:ss")) + messagePreviewContent.text = message.content + messagePreviewAuthor.text = if (message.folderId == MessageFolder.SENT.id) "${context.getString(R.string.message_to)} ${message.recipient}" + else "${context.getString(R.string.message_from)} ${message.sender}" + } + } + + private fun bindAttachment(view: View, attachment: MessageAttachment) { + with(view) { + messagePreviewAttachment.visibility = View.VISIBLE + messagePreviewAttachment.text = attachment.filename + setOnClickListener { + context.openInternetBrowser(attachment.url) { } + } + } + } + + class MessageViewHolder(val view: View) : RecyclerView.ViewHolder(view) + + class DividerViewHolder(val view: View) : RecyclerView.ViewHolder(view) + + class AttachmentViewHolder(val view: View) : RecyclerView.ViewHolder(view) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt index 22231e429..3f52be895 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt @@ -1,6 +1,5 @@ package io.github.wulkanowy.ui.modules.message.preview -import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.Menu @@ -10,8 +9,10 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView @@ -25,6 +26,9 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl @Inject lateinit var presenter: MessagePreviewPresenter + @Inject + lateinit var previewAdapter: MessagePreviewAdapter + private var menuReplyButton: MenuItem? = null private var menuForwardButton: MenuItem? = null @@ -34,18 +38,15 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl override val titleStringId: Int get() = R.string.message_title - override val noSubjectString: String - get() = getString(R.string.message_no_subject) - override val deleteMessageSuccessString: String get() = getString(R.string.message_delete_success) companion object { const val MESSAGE_ID_KEY = "message_id" - fun newInstance(messageId: Long): MessagePreviewFragment { + fun newInstance(message: Message): MessagePreviewFragment { return MessagePreviewFragment().apply { - arguments = Bundle().apply { putLong(MESSAGE_ID_KEY, messageId) } + arguments = Bundle().apply { putSerializable(MESSAGE_ID_KEY, message) } } } } @@ -62,11 +63,16 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) messageContainer = messagePreviewContainer - presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getLong(MESSAGE_ID_KEY) ?: 0L) + presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as Message) } override fun initView() { messagePreviewErrorDetails.setOnClickListener { presenter.onDetailsClick() } + + with(messagePreviewRecycler) { + layoutManager = LinearLayoutManager(context) + adapter = previewAdapter + } } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -86,26 +92,11 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl } } - override fun setSubject(subject: String) { - messagePreviewSubject.text = subject - } - - @SuppressLint("SetTextI18n") - override fun setRecipient(recipient: String) { - messagePreviewAuthor.text = "${getString(R.string.message_to)} $recipient" - } - - @SuppressLint("SetTextI18n") - override fun setSender(sender: String) { - messagePreviewAuthor.text = "${getString(R.string.message_from)} $sender" - } - - override fun setDate(date: String) { - messagePreviewDate.text = getString(R.string.message_date, date) - } - - override fun setContent(content: String) { - messagePreviewContent.text = content + override fun setMessageWithAttachment(item: MessageWithAttachment) { + with(previewAdapter) { + messageWithAttachment = item + notifyDataSetChanged() + } } override fun showProgress(show: Boolean) { @@ -113,7 +104,7 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl } override fun showContent(show: Boolean) { - messagePreviewContentContainer.visibility = if (show) VISIBLE else GONE + messagePreviewRecycler.visibility = if (show) VISIBLE else GONE } override fun showOptions(show: Boolean) { @@ -160,7 +151,7 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putLong(MESSAGE_ID_KEY, presenter.messageId) + outState.putSerializable(MESSAGE_ID_KEY, presenter.message) } override fun onDestroyView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 24abda8ca..7bf9c05e7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -1,14 +1,12 @@ package io.github.wulkanowy.ui.modules.message.preview import io.github.wulkanowy.data.db.entities.Message -import io.github.wulkanowy.data.repositories.message.MessageFolder import io.github.wulkanowy.data.repositories.message.MessageRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider -import io.github.wulkanowy.utils.toFormattedString import timber.log.Timber import javax.inject.Inject @@ -20,61 +18,51 @@ class MessagePreviewPresenter @Inject constructor( private val analytics: FirebaseAnalyticsHelper ) : BasePresenter(errorHandler, studentRepository, schedulers) { - var messageId = 0L - - private var message: Message? = null + var message: Message? = null private lateinit var lastError: Throwable private var retryCallback: () -> Unit = {} - fun onAttachView(view: MessagePreviewView, id: Long) { + fun onAttachView(view: MessagePreviewView, message: Message) { super.onAttachView(view) view.initView() errorHandler.showErrorMessage = ::showErrorViewOnError - loadData(id) + loadData(message) } - private fun onMessageLoadRetry() { + private fun onMessageLoadRetry(message: Message) { view?.run { showErrorView(false) showProgress(true) } - loadData(messageId) + loadData(message) } fun onDetailsClick() { view?.showErrorDetailsDialog(lastError) } - private fun loadData(id: Long) { - Timber.i("Loading message $id preview started") - messageId = id + private fun loadData(message: Message) { + Timber.i("Loading message ${message.messageId} preview started") disposable.apply { clear() add(studentRepository.getCurrentStudent() - .flatMap { messageRepository.getMessage(it, messageId, true) } + .flatMap { messageRepository.getMessage(it, message, true) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { view?.showProgress(false) } .subscribe({ message -> - Timber.i("Loading message $id preview result: Success ") - this@MessagePreviewPresenter.message = message - view?.run { - message.let { - setSubject(if (it.subject.isNotBlank()) it.subject else noSubjectString) - setDate(it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")) - setContent(it.content) - initOptions() - - if (it.folderId == MessageFolder.SENT.id) setRecipient(it.recipient) - else setSender(it.sender) - } + Timber.i("Loading message ${message.message.messageId} preview result: Success ") + this@MessagePreviewPresenter.message = message.message + view?.apply { + setMessageWithAttachment(message) + initOptions() } - analytics.logEvent("load_message_preview", "length" to message.content.length) + analytics.logEvent("load_message_preview", "length" to message.message.content.length) }) { - Timber.i("Loading message $id preview result: An exception occurred ") - retryCallback = { onMessageLoadRetry() } + Timber.i("Loading message ${message.messageId} preview result: An exception occurred ") + retryCallback = { onMessageLoadRetry(message) } errorHandler.dispatch(it) }) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt index d57766273..3d620459c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewView.kt @@ -1,25 +1,16 @@ package io.github.wulkanowy.ui.modules.message.preview import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.ui.base.BaseView interface MessagePreviewView : BaseView { - val noSubjectString: String - val deleteMessageSuccessString: String fun initView() - fun setSubject(subject: String) - - fun setRecipient(recipient: String) - - fun setSender(sender: String) - - fun setDate(date: String) - - fun setContent(content: String) + fun setMessageWithAttachment(item: MessageWithAttachment) fun showProgress(show: Boolean) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt index d6065983d..ce0fc7805 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabFragment.kt @@ -12,6 +12,7 @@ import eu.davidea.flexibleadapter.common.FlexibleItemDecoration import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.repositories.message.MessageFolder import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.modules.main.MainActivity @@ -116,8 +117,8 @@ class MessageTabFragment : BaseFragment(), MessageTabView { messageTabSwipe.isRefreshing = show } - override fun openMessage(messageId: Long) { - (activity as? MainActivity)?.pushView(MessagePreviewFragment.newInstance(messageId)) + override fun openMessage(message: Message) { + (activity as? MainActivity)?.pushView(MessagePreviewFragment.newInstance(message)) } override fun notifyParentDataLoaded() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt index a6f64c2b5..cbdb89b2e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabPresenter.kt @@ -62,7 +62,7 @@ class MessageTabPresenter @Inject constructor( if (item is MessageItem) { Timber.i("Select message ${item.message.id} item") view?.run { - openMessage(item.message.id) + openMessage(item.message) if (item.message.unread) { item.message.unread = false updateItem(item) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt index e5705c739..92115ed33 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/tab/MessageTabView.kt @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.modules.message.tab import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.ui.base.BaseView import io.github.wulkanowy.ui.modules.message.MessageItem @@ -32,7 +33,7 @@ interface MessageTabView : BaseView { fun showRefresh(show: Boolean) - fun openMessage(messageId: Long) + fun openMessage(message: Message) fun notifyParentDataLoaded() } diff --git a/app/src/main/res/drawable/ic_attachment.xml b/app/src/main/res/drawable/ic_attachment.xml new file mode 100644 index 000000000..c18714f5c --- /dev/null +++ b/app/src/main/res/drawable/ic_attachment.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/fragment_message_preview.xml b/app/src/main/res/layout/fragment_message_preview.xml index 4a6f7e9a7..0931990f6 100644 --- a/app/src/main/res/layout/fragment_message_preview.xml +++ b/app/src/main/res/layout/fragment_message_preview.xml @@ -5,55 +5,12 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - - - - - - - + android:layout_height="match_parent" + tools:itemCount="1" + tools:listitem="@layout/item_message_preview" /> + app:layout_constraintEnd_toStartOf="@+id/messageItemDate" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="@tools:sample/lorem/random" /> - + + + diff --git a/app/src/main/res/layout/item_message_attachment.xml b/app/src/main/res/layout/item_message_attachment.xml new file mode 100644 index 000000000..fa30e9af2 --- /dev/null +++ b/app/src/main/res/layout/item_message_attachment.xml @@ -0,0 +1,22 @@ + + + + diff --git a/app/src/main/res/layout/item_message_divider.xml b/app/src/main/res/layout/item_message_divider.xml new file mode 100644 index 000000000..2f4ad3e67 --- /dev/null +++ b/app/src/main/res/layout/item_message_divider.xml @@ -0,0 +1,6 @@ + diff --git a/app/src/main/res/layout/item_message_preview.xml b/app/src/main/res/layout/item_message_preview.xml new file mode 100644 index 000000000..6c130909d --- /dev/null +++ b/app/src/main/res/layout/item_message_preview.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt index 7be870ce7..b540c9e5f 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt @@ -4,6 +4,7 @@ import androidx.room.EmptyResultSetException import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Message +import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.UnitTestInternetObservingStrategy import io.reactivex.Single @@ -47,63 +48,70 @@ class MessageRepositoryTest { @Test fun `throw error when message is not in the db`() { - `when`(local.getMessage(123)).thenReturn(Single.error(EmptyResultSetException("No message in database"))) + val testMessage = Message(1, 1, 1, "", 1, "", "", "", now(), 1, false, 1, 1, false, false) + `when`(local.getMessageWithAttachment(student, testMessage)).thenReturn(Single.error(EmptyResultSetException("No message in database"))) - val message = repo.getMessage(student, 123) - val messageObserver = TestObserver() + val message = repo.getMessage(student, testMessage) + val messageObserver = TestObserver() message.subscribe(messageObserver) messageObserver.assertError(EmptyResultSetException::class.java) } @Test fun `get message when content already in db`() { - `when`(local.getMessage(123)).thenReturn(Single.just( - Message(1, 1, 123, "", 1, "", "", "Test", now(), 1, false, 1, 1, false) - )) + val testMessage = Message(1, 1, 123, "", 1, "", "", "Test", now(), 1, false, 1, 1, false, false) + val messageWithAttachment = MessageWithAttachment(testMessage, emptyList()) - val message = repo.getMessage(student, 123).blockingGet() + `when`(local.getMessageWithAttachment(student, testMessage)).thenReturn(Single.just(messageWithAttachment)) - assertEquals("Test", message.content) + val message = repo.getMessage(student, testMessage).blockingGet() + + assertEquals("Test", message.message.content) } @Test fun `get message when content in db is empty`() { - val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false) + val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false, false) val testMessageWithContent = testMessage.copy(content = "Test") - `when`(local.getMessage(123)) - .thenReturn(Single.just(testMessage)) - .thenReturn(Single.just(testMessageWithContent)) - `when`(remote.getMessagesContent(testMessageWithContent)).thenReturn(Single.just("Test")) + val mWa = MessageWithAttachment(testMessage, emptyList()) + val mWaWithContent = MessageWithAttachment(testMessageWithContent, emptyList()) - val message = repo.getMessage(student, 123).blockingGet() + `when`(local.getMessageWithAttachment(student, testMessage)) + .thenReturn(Single.just(mWa)) + .thenReturn(Single.just(mWaWithContent)) + `when`(remote.getMessagesContentDetails(testMessageWithContent)).thenReturn(Single.just("Test" to emptyList())) - assertEquals("Test", message.content) + val message = repo.getMessage(student, testMessage).blockingGet() + + assertEquals("Test", message.message.content) verify(local).updateMessages(listOf(testMessageWithContent)) } @Test fun `get message when content in db is empty and there is no internet connection`() { - val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, false, 1, 1, false) + val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, false, 1, 1, false, false) + val messageWithAttachment = MessageWithAttachment(testMessage, emptyList()) testObservingStrategy.isInternetConnection = false - `when`(local.getMessage(123)).thenReturn(Single.just(testMessage)) + `when`(local.getMessageWithAttachment(student, testMessage)).thenReturn(Single.just(messageWithAttachment)) - val message = repo.getMessage(student, 123) - val messageObserver = TestObserver() + val message = repo.getMessage(student, testMessage) + val messageObserver = TestObserver() message.subscribe(messageObserver) messageObserver.assertError(UnknownHostException::class.java) } @Test fun `get message when content in db is empty, unread and there is no internet connection`() { - val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false) + val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false, false) + val messageWithAttachment = MessageWithAttachment(testMessage, emptyList()) testObservingStrategy.isInternetConnection = false - `when`(local.getMessage(123)).thenReturn(Single.just(testMessage)) + `when`(local.getMessageWithAttachment(student, testMessage)).thenReturn(Single.just(messageWithAttachment)) - val message = repo.getMessage(student, 123) - val messageObserver = TestObserver() + val message = repo.getMessage(student, testMessage) + val messageObserver = TestObserver() message.subscribe(messageObserver) messageObserver.assertError(UnknownHostException::class.java) } From 394e3bb79ce9dd86bb42271b0dc9a9ef326b92ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Thu, 2 Apr 2020 22:43:03 +0200 Subject: [PATCH 29/61] Add firebase messaging (#740) --- app/build.gradle | 11 +++--- app/src/main/AndroidManifest.xml | 11 +++++- .../wulkanowy/services/ServicesModule.kt | 5 +++ .../services/sync/channels/PushChannel.kt | 32 ++++++++++++++++++ .../main/res/drawable-hdpi/ic_stat_push.png | Bin 0 -> 724 bytes .../main/res/drawable-mdpi/ic_stat_push.png | Bin 0 -> 470 bytes .../main/res/drawable-xhdpi/ic_stat_push.png | Bin 0 -> 955 bytes .../main/res/drawable-xxhdpi/ic_stat_push.png | Bin 0 -> 1469 bytes .../res/drawable-xxxhdpi/ic_stat_push.png | Bin 0 -> 2025 bytes app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 14 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/services/sync/channels/PushChannel.kt create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_push.png create mode 100644 app/src/main/res/drawable-mdpi/ic_stat_push.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_push.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_stat_push.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_stat_push.png diff --git a/app/build.gradle b/app/build.gradle index 4a9755179..9cae14d55 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -169,7 +169,7 @@ dependencies { implementation "eu.davidea:flexible-adapter-ui:1.0.0" implementation "com.aurelhubert:ahbottomnavigation:2.3.4" implementation "com.ncapdevi:frag-nav:3.3.0" - implementation "com.github.YarikSOffice:lingver:1.1.0" + implementation "com.github.YarikSOffice:lingver:1.2.1" implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6" implementation "io.reactivex.rxjava2:rxandroid:2.1.1" @@ -182,11 +182,14 @@ dependencies { implementation "fr.bipi.treessence:treessence:0.3.2" implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation 'com.wdullaer:materialdatetimepicker:4.2.3' + implementation "io.coil-kt:coil:0.9.5" - implementation("io.coil-kt:coil:0.9.5") - - playImplementation "com.google.firebase:firebase-core:17.3.0" + playImplementation 'com.google.firebase:firebase-analytics:17.3.0' + playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.4' + playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.4" + playImplementation "com.google.firebase:firebase-messaging:20.1.0" playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1" + playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 694c8053a..42c754756 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,7 +22,8 @@ + android:theme="@style/WulkanowyTheme.SplashScreen" + tools:ignore="LockedOrientationActivity"> @@ -112,5 +113,13 @@ + + + + diff --git a/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt b/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt index 0b1b357ac..7240a50bb 100644 --- a/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt +++ b/app/src/main/java/io/github/wulkanowy/services/ServicesModule.kt @@ -15,6 +15,7 @@ import io.github.wulkanowy.services.sync.channels.LuckyNumberChannel import io.github.wulkanowy.services.sync.channels.NewGradesChannel import io.github.wulkanowy.services.sync.channels.NewMessagesChannel import io.github.wulkanowy.services.sync.channels.NewNotesChannel +import io.github.wulkanowy.services.sync.channels.PushChannel import io.github.wulkanowy.services.sync.works.AttendanceSummaryWork import io.github.wulkanowy.services.sync.works.AttendanceWork import io.github.wulkanowy.services.sync.works.CompletedLessonWork @@ -126,4 +127,8 @@ abstract class ServicesModule { @Binds @IntoSet abstract fun provideNewNotesChannel(channel: NewNotesChannel): Channel + + @Binds + @IntoSet + abstract fun providePushChannel(channel: PushChannel): Channel } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/channels/PushChannel.kt b/app/src/main/java/io/github/wulkanowy/services/sync/channels/PushChannel.kt new file mode 100644 index 000000000..a0e24ab45 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/services/sync/channels/PushChannel.kt @@ -0,0 +1,32 @@ +package io.github.wulkanowy.services.sync.channels + +import android.annotation.TargetApi +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import androidx.core.app.NotificationManagerCompat +import io.github.wulkanowy.R +import javax.inject.Inject + +@TargetApi(26) +class PushChannel @Inject constructor( + private val notificationManager: NotificationManagerCompat, + private val context: Context +) : Channel { + + companion object { + const val CHANNEL_ID = "push_channel" + } + + override fun create() { + notificationManager.createNotificationChannel( + NotificationChannel(CHANNEL_ID, context.getString(R.string.channel_push), NotificationManager.IMPORTANCE_HIGH) + .apply { + enableLights(true) + enableVibration(true) + lockscreenVisibility = Notification.VISIBILITY_PUBLIC + } + ) + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_stat_push.png b/app/src/main/res/drawable-hdpi/ic_stat_push.png new file mode 100644 index 0000000000000000000000000000000000000000..84578183f4c91b489e4234179e2663d6d6c6daa4 GIT binary patch literal 724 zcmeAS@N?(olHy`uVBq!ia0y~yU{C>J4mJh`hKCF@W-u@?&GvM045_&Fc80Hqn4`q; ztC#Fd9$pnX<;}kF!Vp$eeln<$}1&GZvnZ z*}?LtNx&*e!S_Rp)djCow%YK`rMT>tMe|I4uY{?s6a>tOVU zm?@<9qMV~ z&;N*2DM;1%D7Vk|F^MbQo6YC6{*Q>1IPdquo8GDq?cQa7F|1uKIO}_=ZLeEdL44;i zk?Gg9Ip23>KXPELSbxRyyYq^W;_aFV(}UbDDeqD85l@O;SupS z$EEt+ROvY9$j@6QBU*FTaJFgi#64r?z|pUlE1#c{V-a-&M+G0zt(y_<~InZF5K z5xHe=r+9hRpGE&UN{p_`30;wV7qec&a#Mxv(%1Qwt1e9OewhfF9Xp@B iOt`DF^yl&GS`Ty;!(@2Oe={&JFnGH9xvXh21gPbhN^>8bB64$q&JxWfIug=eE@G2&3Oz3^Zyvk8{>n+;}rqBn$PZE!Z*qkZdf9U*NGtrROp*9LGQ3n-HJe1Z+ zzMS%1#QXsNJO}oSaGn<@R_&E=iA>-;^TC4cR8F7fv!f48D*qm2>c8(`ID=vPp$GTY zR;-MWdFnl_hvP)D+Ck>?zwb)4v^-!8?J82aVixAe81ZChp*h=Wr=DZC`Fz*OU->*^ zR^oU6YCoqCkNL~G-!+*OXck>rBYd9ixKo1smQ0=%i^Uo<4c#p{tt8KAGZp3uic3wF zn{aNY7h7nAgJ^!ij}<13iM@{E>({gNC(Y|y8zVL6hR!~=)<3p(#ReH7Qp~4zAGZG~ c{FCYIlbdoWH+`2eFfcH9y85}Sb4q9e0Nek}ssI20 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_push.png b/app/src/main/res/drawable-xhdpi/ic_stat_push.png new file mode 100644 index 0000000000000000000000000000000000000000..79b38e63f9ad078456fa4d1509540a21fba84fba GIT binary patch literal 955 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F#vU655I!qdhiuO`v8&9*u7^;w$I>ye_?CM-s^u~Uthl}V8!)+%*H&* zTx*!j7`+>}9>`iC_=By4snj9uLPtMCp7gcc=ztD?wsj1$ZMM6)Qhs{cuxBvYNuGN< zGk@KYm;)ZYu74HwOZ<2@se&nk;ZWRUdA>hBj6XB$cAhJm{^UN>=|6M!bjM71&v@z& z-|U$Ow0Q%~?020Ay>aNP#0thw%|gH3navw^9NGS!(Rf9yg-8nXLD{B;^A1nqPgU~? ze-vAAZTgINK@N7R*@+8nn0)xPUIy!&Hd!gpc4yJg011;%kq+Bucm}1UswDr&s1rk&>)aKfMAR^$wkQ~a6NTDt3m&o9iF{O6Q(>#rGZ4tLh~7&EUB z+H}s|XTp*HrDezX8G}_^qIMcYp5e^h{6YL!wQfRl%L%Df(Vpj%Usm?C{yoUKo^_5W z$A%AKhDNFvVWM*M-@axuws>BQGLf<`a{Z8TXtqgKfey~!U zDbC{`1NYp&n$N{^8Lw|=*pZ{uvR7Mq?vr+}vM9GAYmJ}QXU=)vGZxJVz7#14cYMQi zb^f-(o}eRhQ%blVZZU~{fZFXaP-iF9OX&AZ?k2%Dl~em{e=a- zn49PHXFXoFw5fQz96QrG?_>5WUIyp7*(DVR$vyvd%~GHsXk&)m^)I*A2yM9htTt?8 zfnUn^ruPj^?o+~2Hec>3igdT0eyMlTzuh@pD@;DNd7Z6!!SOZ9;f?-_o!9x4pY2Iu QU|?YIboFyt=akR{0Er8<^8f$< literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_push.png b/app/src/main/res/drawable-xxhdpi/ic_stat_push.png new file mode 100644 index 0000000000000000000000000000000000000000..bc33cb5b142c5c17c3168aea3d94f5842ad5a6e3 GIT binary patch literal 1469 zcmeAS@N?(olHy`uVBq!ia0y~yVDJE84mJh`hS0a0-5D5ITRdGHLn>~)jp6PH4HcQ| zJSXB8=((Y&OvWr3T}qzQqV9ZtGu{v;?wX_!e&T{cZ#M%3G7 z^9m0ElS=`Y?VhBc@iJ0!Km9-EdYf&9#oTJU@^`iG?^)*`PLg~7w))+@*LRE0-TVE< zyt2~rq^Doh>WX>c3{#l?HaOM2XIvnp!St%(e#7Ylh6#2B!M8kLa-Cu0V+`MueTij` zK-~X#D^tZU=&gMc!nl0TwA0C%N=uDDXa(^9dE2Udeo5mDvjcAr@W=fqVw>Ul-9yWA z>Yf#Dy2g{dE`;eDf65g)xs%&shGLVLTJM~!2m5&hoF5)6T97>HgeJ?sGYpm@>{C?= zv#zE!$Z#nfS1V17lQFc6ZdmBqSADNz!W`}c50_lXFA;Y`tp?Wy9{eeBMP2(t@O-Z^*KbUBZ~D)?%SgqE`_8&RunJ^RA|v^ z5^sFp$hkA>)z&S|V)rgP$Sc?%KlR^Ji@i(t+Ukp$>P=j4;u%c&uE((ZuC*sKH8jjVE?p( zk8hbwy4-tx;$(;DqtA>rB#}eC(xkgM!w{ds5|1Y#A~?{4Que)ZG>7*V(8nEW5-! zqwo&rC0PzX;V<_BYwUugva1=IGTy$DOmDKgB69cl20#9Je4DO#C$rjGS8JbRk^N{` zwS0lG|K_$5!7s;HR9@&jttnJl9ud5#!tuoRe-|yxJtfwcubQA#6%4;A;@(uk%jwTi70t`u@-!&4kg4FxR}QOltp>pj7S|r!v6=rVdu@Q8;mOL- zy_&P1luUahb>CfXeLjnn=`Qs@=Wcwgt4=VQe{uE_6+af+B!h1omh8W@!2VXje!c^r zown~y?^?ad_kv8f-9aYD{kIkge3SezXUA9Vcee#AZm0K%KX$n=U9A64ZByOK zy|=M;Rg3?8)8qZv$I6sV&NCd&Ad!<0DRH zMzNb7M*4=-=5OPyI(ccO*0p#!r`31uPPRGC|8wr~C-46`LSH&to$qhRvv;<5aOqLB z+Rcv}-Tqr#(3XA@;%Q&z0P-=g(yrWE)4E9YN0#4Bf35^v(ItiOO+cln~#d-QIm zMmt9dM=sZ~uDNq*g6p)E9s!mMI@b8#zPA3T@(KgasE1ap8b5ggHf@;tZ&EF{?7CXr zoFcjHbE3|Eno#goTTsx%d(%XzE4lSc-1l8+bLD$#Q_o`C_VC_<&w>Ia0g2hIhxcZr z*BbFOU1K%)H>2dr9;-#mU+}f=)wh0DaX8xP++|&ZeNGbUtKxt1e6oD{_f8^D)SY$~ z#pTN%THI7IZr!+IZn-}Ti)glAR7{Tj%PSL(^5y0&{8+uz(7nyaZ}JVA0PK+Z)MnV(MN_ti1m>85kHCJYD@<);T3K0RTa&u8{x$ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_stat_push.png b/app/src/main/res/drawable-xxxhdpi/ic_stat_push.png new file mode 100644 index 0000000000000000000000000000000000000000..b354bd06c4aa4b93f2e9bde47fa538e374c153e0 GIT binary patch literal 2025 zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4mJh`hDS5XEf^TsH+Z@@hE&{o8_S&|>MF97 zRi~~&Y+=LG4pkgb2Oj7v$manBb7Sm?OiX%VP_Z+Z8WS z6_18Ri`)bp6(6xb4PIQ+#k%y*vFgvyTF)Bnw%%;L`}e(fcb=%|zB%(|&SmrJ=l86C zOPO9;<~!Rg_m)yZ%Y?9ol3&Hy2e=z-8`uuiH^?@mGhWZw_N2p?@ebPz&Is-sycP^M z_;0X9a7D0KxSyQIY~ge!SAN0fw6LB(jScHNt8TBkxmEqY;Q`i1y|FAMS9Id{U3n1y zCui51IqLVK!q5Iv{j{EGkN=;o+Zika)%S5P5ZTbjlKh{^&28!*p#zaZdlq)jk~RG# z&FnYf$i_)4I4_74STwR|^a%aj*&r{}@n>y=TA<>7^9LzS0{zy{Qyatr757U%Sk9vO zf2oFDg}XY(&li=ct{30N%w>2opGn01>ihpn37?iTt?T`??)znilgDk{U$1DFoyXtt zXFtPFs|Ri#>AT*3Ki$W4igBjZol4J^POgrlJvZi?{4Q;5Tl+d=+3HzoN7xqMUM=~& z+u*M2BG&Q?;Rc3FMb56;!%_KV{nwrceWj`iK{hYf`OX!{WpTRnBQta5%};(Ucg>h; zmPLN*`xBk(#5Tk1%mtrHb%*-45}y{*n$;APQSso6o@JSn~#cC2H4 zu;cKPD)X~jEH`@dNUtsvyKehf$!V95@mck)>0R=zrOa{cHmO26*#Qbpl_D%RG#ri?ZnJ5b)_df!)6F?`%e4g- z*j@SR5Fy3%!@aEi6sNh*lP`BeE(V#HpJDnUsPZsx+1-?9|F_Tl62Hu$Ve-PY?5&-) znhp+Y4Uc*p=54oBRex*w*M7wb}jQ50R{Bc_5+j+87*y3+_po&B6i&a_~m!5PS zc=FrWI(747&)dGoend~?Fg~p2(05=7zeKj#N0VJ=yN#=gj@?|~(U81w)f!=&*P+K+ zwD)b@Stpl1XD65U)#a_84P1?!-;HA86$<`3Zd2o^lV2CW5OZ!;yK6(O+2p&Yb?l{C zJ+%^!?Tq`_*t;=NVLxx|=CwJDm($uW&k(GgreQ5D!^YUgm1_>KrH*V$ylEC0_O6X8wtm+6>q4IsD!(oK$4Qy&=x2VeOo6t&>i( z9-A$8A=sps^?l)l-q|q|*E}&-EqY&JeQ@6Wqi?2j^FJ$p)%bOzwRn#3w-ugYj772& zuFZV;*ws~fReZ*r7h;pE=jJ@-ygRjrX^NG?stXtP*>>(-?Y=b8C|%-t+~!=rN6CE) z$~SRtxWwq#FLmp@`n?-blYjrcv`kh`;-seFRp0;a2v^Tr@K~GCUTel5_Bs2^**<7Wq#Is;s`u+}TgAs*X_are zLRxP`q=Osp%X2t1JQXX>^-GFpdUfRkzm~7+PiE2l8C;et&otX{f9N_p=Y4^sQf0V_ zd#-z3@vM8nnWA$F(|+h2C~4fe+qSb)@teqYCY^5ypSC{vWK?V;UUS8r@fi2JZ`m<@ z#;19Ivhq#RS#+)6_}*nZE`u1Qiy_aGWS*?Q!ueA|{^wz5CbxoPM}#M_*9a-ZH+8qi z_O+frKXDUNg{0cOPX4&bh21qm57a#E?u7|-$|_mi2;iSCcc`tt;E-PuwQr+&%T{k3X4T{AjuJY-`aSkK0|?R(*OQyrF%%z{8$?b+z#7 z68;;{rNsMAiikgyklDRzqFL^(Et!|y-qtTa^tm^4UX(Ed0|SGntDnm{r-UW|)1Glückliche Nummer Neue Nachrichten Neue Eintragen + Push-Benachrichtigungen Debuggen diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index c80137b1e..33981e8ee 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -385,6 +385,7 @@ Nowe oceny Nowe wiadomości Nowe uwagi + Powiadomienia push Debugowanie diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e5530400f..7e7313425 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -382,6 +382,7 @@ Счастливый номер Новые сообщения Новые заметки + Push-уведомления Дебаг diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index cd1c3b5d0..522eb8729 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -383,6 +383,7 @@ Нові оцінки Нові повідомлення Нові нотатки + Повідомлення pushs Дебаг diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 30cc086de..1cd5aad65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -368,6 +368,7 @@ Lucky number New messages New notes + Push notifications Debug From 651be69ad2972e55924039425b34834a5d4576d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Thu, 2 Apr 2020 22:47:10 +0200 Subject: [PATCH 30/61] Add firebase messaging (#740) From 18c1153e12c5b436414e8729c3dc852ff2522cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Fri, 3 Apr 2020 17:39:36 +0200 Subject: [PATCH 31/61] Add mark as done feature in homework (#743) --- app/build.gradle | 2 +- .../25.json | 1744 +++++++++++++++++ .../github/wulkanowy/data/db/AppDatabase.kt | 6 +- .../io/github/wulkanowy/data/db/Converters.kt | 10 + .../wulkanowy/data/db/entities/Homework.kt | 6 +- .../data/db/migrations/Migration25.kt | 12 + .../repositories/homework/HomeworkLocal.kt | 4 + .../repositories/homework/HomeworkRemote.kt | 3 +- .../homework/HomeworkRepository.kt | 9 + .../ui/modules/homework/HomeworkDialog.kt | 49 - .../ui/modules/homework/HomeworkFragment.kt | 7 +- .../ui/modules/homework/HomeworkItem.kt | 5 +- .../ui/modules/homework/HomeworkPresenter.kt | 4 + .../homework/details/HomeworkDetailsDialog.kt | 79 + .../details/HomeworkDetailsPresenter.kt | 44 + .../homework/details/HomeworkDetailsView.kt | 10 + .../wulkanowy/ui/modules/main/MainModule.kt | 5 + app/src/main/res/drawable/ic_check.xml | 9 + app/src/main/res/layout/dialog_homework.xml | 46 +- app/src/main/res/layout/item_homework.xml | 71 +- app/src/main/res/values-de/strings.xml | 3 + app/src/main/res/values-pl/strings.xml | 3 + app/src/main/res/values-ru/strings.xml | 3 + app/src/main/res/values-uk/strings.xml | 3 + app/src/main/res/values/api_hosts.xml | 2 +- app/src/main/res/values/strings.xml | 3 + 26 files changed, 2060 insertions(+), 82 deletions(-) create mode 100644 app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration25.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsView.kt create mode 100644 app/src/main/res/drawable/ic_check.xml diff --git a/app/build.gradle b/app/build.gradle index 9cae14d55..501620f71 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,7 +128,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:44725a9" + implementation "io.github.wulkanowy:sdk:bff34b1" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json new file mode 100644 index 000000000..e99a11d4a --- /dev/null +++ b/app/schemas/io.github.wulkanowy.data.db.AppDatabase/25.json @@ -0,0 +1,1744 @@ +{ + "formatVersion": 1, + "database": { + "version": 25, + "identityHash": "d101f5a26a024f62e6fee161e421b882", + "entities": [ + { + "tableName": "Students", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `scrapper_base_url` TEXT NOT NULL, `mobile_base_url` TEXT NOT NULL, `login_type` TEXT NOT NULL, `login_mode` TEXT NOT NULL, `certificate_key` TEXT NOT NULL, `private_key` TEXT NOT NULL, `is_parent` INTEGER NOT NULL, `email` TEXT NOT NULL, `password` TEXT NOT NULL, `symbol` TEXT NOT NULL, `student_id` INTEGER NOT NULL, `user_login_id` INTEGER NOT NULL, `student_name` TEXT NOT NULL, `school_id` TEXT NOT NULL, `school_short` TEXT NOT NULL, `school_name` TEXT NOT NULL, `class_name` TEXT NOT NULL, `class_id` INTEGER NOT NULL, `is_current` INTEGER NOT NULL, `registration_date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "scrapperBaseUrl", + "columnName": "scrapper_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "mobileBaseUrl", + "columnName": "mobile_base_url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginType", + "columnName": "login_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginMode", + "columnName": "login_mode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "certificateKey", + "columnName": "certificate_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "privateKey", + "columnName": "private_key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isParent", + "columnName": "is_parent", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "email", + "columnName": "email", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "symbol", + "columnName": "symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userLoginId", + "columnName": "user_login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentName", + "columnName": "student_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolSymbol", + "columnName": "school_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolShortName", + "columnName": "school_short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolName", + "columnName": "school_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "className", + "columnName": "class_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isCurrent", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registrationDate", + "columnName": "registration_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Students_email_symbol_student_id_school_id_class_id", + "unique": true, + "columnNames": [ + "email", + "symbol", + "student_id", + "school_id", + "class_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Students_email_symbol_student_id_school_id_class_id` ON `${TABLE_NAME}` (`email`, `symbol`, `student_id`, `school_id`, `class_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Semesters", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_current` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `diary_name` TEXT NOT NULL, `school_year` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `semester_name` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "current", + "columnName": "is_current", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryName", + "columnName": "diary_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "schoolYear", + "columnName": "school_year", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterName", + "columnName": "semester_name", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_Semesters_student_id_diary_id_semester_id", + "unique": true, + "columnNames": [ + "student_id", + "diary_id", + "semester_id" + ], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Semesters_student_id_diary_id_semester_id` ON `${TABLE_NAME}` (`student_id`, `diary_id`, `semester_id`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "Exams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `group` TEXT NOT NULL, `type` TEXT NOT NULL, `description` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `number` INTEGER NOT NULL, `start` INTEGER NOT NULL, `end` INTEGER NOT NULL, `date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `subjectOld` TEXT NOT NULL, `group` TEXT NOT NULL, `room` TEXT NOT NULL, `roomOld` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacherOld` TEXT NOT NULL, `info` TEXT NOT NULL, `student_plan` INTEGER NOT NULL, `changes` INTEGER NOT NULL, `canceled` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "start", + "columnName": "start", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "end", + "columnName": "end", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subjectOld", + "columnName": "subjectOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "group", + "columnName": "group", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "room", + "columnName": "room", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roomOld", + "columnName": "roomOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherOld", + "columnName": "teacherOld", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "info", + "columnName": "info", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "isStudentPlan", + "columnName": "student_plan", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "changes", + "columnName": "changes", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canceled", + "columnName": "canceled", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Attendance", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `time_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `exemption` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `excused` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `excusable` INTEGER NOT NULL, `excuse_status` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "timeId", + "columnName": "time_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excused", + "columnName": "excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deleted", + "columnName": "deleted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excusable", + "columnName": "excusable", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "excuseStatus", + "columnName": "excuse_status", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "AttendanceSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `subject_id` INTEGER NOT NULL, `month` INTEGER NOT NULL, `presence` INTEGER NOT NULL, `absence` INTEGER NOT NULL, `absence_excused` INTEGER NOT NULL, `absence_for_school_reasons` INTEGER NOT NULL, `lateness` INTEGER NOT NULL, `lateness_excused` INTEGER NOT NULL, `exemption` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subject_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "month", + "columnName": "month", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "presence", + "columnName": "presence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceExcused", + "columnName": "absence_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "absenceForSchoolReasons", + "columnName": "absence_for_school_reasons", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lateness", + "columnName": "lateness", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "latenessExcused", + "columnName": "lateness_excused", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "exemption", + "columnName": "exemption", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `entry` TEXT NOT NULL, `value` REAL NOT NULL, `modifier` REAL NOT NULL, `comment` TEXT NOT NULL, `color` TEXT NOT NULL, `grade_symbol` TEXT NOT NULL, `description` TEXT NOT NULL, `weight` TEXT NOT NULL, `weightValue` REAL NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "entry", + "columnName": "entry", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "modifier", + "columnName": "modifier", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "comment", + "columnName": "comment", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "gradeSymbol", + "columnName": "grade_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "weightValue", + "columnName": "weightValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesSummary", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `position` INTEGER NOT NULL, `subject` TEXT NOT NULL, `predicted_grade` TEXT NOT NULL, `final_grade` TEXT NOT NULL, `proposed_points` TEXT NOT NULL, `final_points` TEXT NOT NULL, `points_sum` TEXT NOT NULL, `average` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "position", + "columnName": "position", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "predictedGrade", + "columnName": "predicted_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalGrade", + "columnName": "final_grade", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "proposedPoints", + "columnName": "proposed_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "finalPoints", + "columnName": "final_points", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pointsSum", + "columnName": "points_sum", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "average", + "columnName": "average", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `grade` INTEGER NOT NULL, `amount` INTEGER NOT NULL, `is_semester` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "grade", + "columnName": "grade", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "amount", + "columnName": "amount", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "is_semester", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GradesPointsStatistics", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `others` REAL NOT NULL, `student` REAL NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "others", + "columnName": "others", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "student", + "columnName": "student", + "affinity": "REAL", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `recipient_name` TEXT NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `date` INTEGER NOT NULL, `folder_id` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `unread_by` INTEGER NOT NULL, `read_by` INTEGER NOT NULL, `removed` INTEGER NOT NULL, `has_attachments` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sender", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "recipient", + "columnName": "recipient_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "folderId", + "columnName": "folder_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unread", + "columnName": "unread", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unreadBy", + "columnName": "unread_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readBy", + "columnName": "read_by", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "removed", + "columnName": "removed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasAttachments", + "columnName": "has_attachments", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MessageAttachments", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`real_id` INTEGER NOT NULL, `message_id` INTEGER NOT NULL, `one_drive_id` TEXT NOT NULL, `url` TEXT NOT NULL, `filename` TEXT NOT NULL, PRIMARY KEY(`real_id`))", + "fields": [ + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "message_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "oneDriveId", + "columnName": "one_drive_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "filename", + "columnName": "filename", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "real_id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_read` INTEGER NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `category` TEXT NOT NULL, `category_type` INTEGER NOT NULL, `is_points_show` INTEGER NOT NULL, `points` INTEGER NOT NULL, `content` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isRead", + "columnName": "is_read", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "category", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "categoryType", + "columnName": "category_type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isPointsShow", + "columnName": "is_points_show", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "points", + "columnName": "points", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Homework", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_done` INTEGER NOT NULL, `semester_id` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `entry_date` INTEGER NOT NULL, `subject` TEXT NOT NULL, `content` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `attachments` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDone", + "columnName": "is_done", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semesterId", + "columnName": "semester_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "entryDate", + "columnName": "entry_date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "content", + "columnName": "content", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "attachments", + "columnName": "attachments", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LuckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_notified` INTEGER NOT NULL, `student_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `lucky_number` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isNotified", + "columnName": "is_notified", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "luckyNumber", + "columnName": "lucky_number", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "CompletedLesson", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `diary_id` INTEGER NOT NULL, `date` INTEGER NOT NULL, `number` INTEGER NOT NULL, `subject` TEXT NOT NULL, `topic` TEXT NOT NULL, `teacher` TEXT NOT NULL, `teacher_symbol` TEXT NOT NULL, `substitution` TEXT NOT NULL, `absence` TEXT NOT NULL, `resources` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "diaryId", + "columnName": "diary_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "number", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "topic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacher", + "columnName": "teacher", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "teacherSymbol", + "columnName": "teacher_symbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "substitution", + "columnName": "substitution", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "absence", + "columnName": "absence", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "resources", + "columnName": "resources", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "ReportingUnits", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` INTEGER NOT NULL, `short` TEXT NOT NULL, `sender_id` INTEGER NOT NULL, `sender_name` TEXT NOT NULL, `roles` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderId", + "columnName": "sender_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "sender_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "roles", + "columnName": "roles", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Recipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `real_id` TEXT NOT NULL, `name` TEXT NOT NULL, `real_name` TEXT NOT NULL, `login_id` INTEGER NOT NULL, `unit_id` INTEGER NOT NULL, `role` INTEGER NOT NULL, `hash` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "realId", + "columnName": "real_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "realName", + "columnName": "real_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "login_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "unitId", + "columnName": "unit_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "role", + "columnName": "role", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hash", + "columnName": "hash", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "MobileDevices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `device_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `date` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "device_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "Teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `subject` TEXT NOT NULL, `name` TEXT NOT NULL, `short_name` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "subject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shortName", + "columnName": "short_name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "School", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `student_id` INTEGER NOT NULL, `class_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `address` TEXT NOT NULL, `contact` TEXT NOT NULL, `headmaster` TEXT NOT NULL, `pedagogue` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentId", + "columnName": "student_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "classId", + "columnName": "class_id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "contact", + "columnName": "contact", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "headmaster", + "columnName": "headmaster", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "pedagogue", + "columnName": "pedagogue", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd101f5a26a024f62e6fee161e421b882')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index 695c2d870..762c52f8f 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -67,6 +67,7 @@ import io.github.wulkanowy.data.db.migrations.Migration21 import io.github.wulkanowy.data.db.migrations.Migration22 import io.github.wulkanowy.data.db.migrations.Migration23 import io.github.wulkanowy.data.db.migrations.Migration24 +import io.github.wulkanowy.data.db.migrations.Migration25 import io.github.wulkanowy.data.db.migrations.Migration3 import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration5 @@ -109,7 +110,7 @@ import javax.inject.Singleton abstract class AppDatabase : RoomDatabase() { companion object { - const val VERSION_SCHEMA = 24 + const val VERSION_SCHEMA = 25 fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array { return arrayOf( @@ -135,7 +136,8 @@ abstract class AppDatabase : RoomDatabase() { Migration21(), Migration22(), Migration23(), - Migration24() + Migration24(), + Migration25() ) } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt b/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt index 73a04d236..294f73d3d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/Converters.kt @@ -48,4 +48,14 @@ class Converters { fun gsonToIntList(value: String): List { return Gson().fromJson(value, object : TypeToken>() {}.type) } + + @TypeConverter + fun stringPairListToGson(list: List>): String { + return Gson().toJson(list) + } + + @TypeConverter + fun gsonToStringPairList(value: String): List> { + return Gson().fromJson(value, object : TypeToken>>() {}.type) + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt index a22df0961..cd7d153e9 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Homework.kt @@ -27,10 +27,14 @@ data class Homework( val teacher: String, @ColumnInfo(name = "teacher_symbol") - val teacherSymbol: String + val teacherSymbol: String, + val attachments: List> ) : Serializable { @PrimaryKey(autoGenerate = true) var id: Long = 0 + + @ColumnInfo(name = "is_done") + var isDone: Boolean = false } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration25.kt b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration25.kt new file mode 100644 index 000000000..4749bac73 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/migrations/Migration25.kt @@ -0,0 +1,12 @@ +package io.github.wulkanowy.data.db.migrations + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration25 : Migration(24, 25) { + + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0") + database.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"") + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt index 671ecafd7..fdae45182 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkLocal.kt @@ -19,6 +19,10 @@ class HomeworkLocal @Inject constructor(private val homeworkDb: HomeworkDao) { homeworkDb.deleteAll(homework) } + fun updateHomework(homework: List) { + homeworkDb.updateAll(homework) + } + fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe> { return homeworkDb.loadAll(semester.semesterId, semester.studentId, startDate, endDate) .filter { it.isNotEmpty() } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt index 189499dbe..bbaea1e34 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt @@ -23,7 +23,8 @@ class HomeworkRemote @Inject constructor(private val sdk: Sdk) { subject = it.subject, content = it.content, teacher = it.teacher, - teacherSymbol = it.teacherSymbol + teacherSymbol = it.teacherSymbol, + attachments = it.attachments.map { attachment -> attachment.url to attachment.name } ) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt index 3f924944d..e506bdb94 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt @@ -7,6 +7,7 @@ import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.uniqueSubtract +import io.reactivex.Completable import io.reactivex.Single import org.threeten.bp.LocalDate import java.net.UnknownHostException @@ -36,4 +37,12 @@ class HomeworkRepository @Inject constructor( }.flatMap { local.getHomework(semester, monday, friday).toSingle(emptyList()) }) } } + + fun toggleDone(homework: Homework): Completable { + return Completable.fromCallable { + local.updateHomework(listOf(homework.apply { + isDone = !isDone + })) + } + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkDialog.kt deleted file mode 100644 index 427841886..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkDialog.kt +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.wulkanowy.ui.modules.homework - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.DialogFragment -import io.github.wulkanowy.R -import io.github.wulkanowy.data.db.entities.Homework -import io.github.wulkanowy.utils.toFormattedString -import kotlinx.android.synthetic.main.dialog_homework.* - -class HomeworkDialog : DialogFragment() { - - private lateinit var homework: Homework - - companion object { - private const val ARGUMENT_KEY = "Item" - - fun newInstance(homework: Homework): HomeworkDialog { - return HomeworkDialog().apply { - arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) } - } - } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setStyle(STYLE_NO_TITLE, 0) - arguments?.run { - homework = getSerializable(HomeworkDialog.ARGUMENT_KEY) as Homework - } - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.dialog_homework, container, false) - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - - homeworkDialogDate.text = homework.date.toFormattedString() - homeworkDialogEntryDate.text = homework.entryDate.toFormattedString() - homeworkDialogSubject.text = homework.subject - homeworkDialogTeacher.text = homework.teacher - homeworkDialogContent.text = homework.content - homeworkDialogClose.setOnClickListener { dismiss() } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt index 3f8f1359a..a011a015c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkFragment.kt @@ -13,6 +13,7 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.ui.modules.homework.details.HomeworkDetailsDialog import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.dpToPx @@ -73,6 +74,10 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView { homeworkAdapter.updateDataSet(data, true) } + fun onReloadList() { + presenter.reloadData() + } + override fun clearData() { homeworkAdapter.clear() } @@ -118,7 +123,7 @@ class HomeworkFragment : BaseFragment(), HomeworkView, MainView.TitledView { } override fun showTimetableDialog(homework: Homework) { - (activity as? MainActivity)?.showDialogFragment(HomeworkDialog.newInstance(homework)) + (activity as? MainActivity)?.showDialogFragment(HomeworkDetailsDialog.newInstance(homework)) } override fun onSaveInstanceState(outState: Bundle) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt index 2de9233f2..3c2dd7baf 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkItem.kt @@ -24,6 +24,8 @@ class HomeworkItem(header: HomeworkHeader, val homework: Homework) : homeworkItemSubject.text = homework.subject homeworkItemTeacher.text = homework.teacher homeworkItemContent.text = homework.content + homeworkItemCheckImage.visibility = if (homework.isDone) View.VISIBLE else View.GONE + homeworkItemAttachmentImage.visibility = if (!homework.isDone && homework.attachments.isNotEmpty()) View.VISIBLE else View.GONE } } @@ -43,7 +45,8 @@ class HomeworkItem(header: HomeworkHeader, val homework: Homework) : return result } - class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), LayoutContainer { + class ViewHolder(val view: View, adapter: FlexibleAdapter<*>) : + FlexibleViewHolder(view, adapter), LayoutContainer { override val containerView: View get() = contentView } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt index 7e1da314b..26d16b1df 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt @@ -95,6 +95,10 @@ class HomeworkPresenter @Inject constructor( }) } + fun reloadData() { + loadData(currentDate, false) + } + private fun loadData(date: LocalDate, forceRefresh: Boolean = false) { Timber.i("Loading homework data started") currentDate = date diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt new file mode 100644 index 000000000..58622848e --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt @@ -0,0 +1,79 @@ +package io.github.wulkanowy.ui.modules.homework.details + +import android.annotation.SuppressLint +import android.os.Bundle +import android.text.method.LinkMovementMethod +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.text.HtmlCompat +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Homework +import io.github.wulkanowy.ui.base.BaseDialogFragment +import io.github.wulkanowy.ui.modules.homework.HomeworkFragment +import io.github.wulkanowy.utils.toFormattedString +import kotlinx.android.synthetic.main.dialog_homework.* +import javax.inject.Inject + +class HomeworkDetailsDialog : BaseDialogFragment(), HomeworkDetailsView { + + @Inject + lateinit var presenter: HomeworkDetailsPresenter + + private lateinit var homework: Homework + + companion object { + private const val ARGUMENT_KEY = "Item" + + fun newInstance(homework: Homework): HomeworkDetailsDialog { + return HomeworkDetailsDialog().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, homework) } + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, 0) + arguments?.run { + homework = getSerializable(ARGUMENT_KEY) as Homework + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.dialog_homework, container, false) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + presenter.onAttachView(this) + } + + @SuppressLint("SetTextI18n") + override fun initView() { + homeworkDialogDate.text = homework.date.toFormattedString() + homeworkDialogEntryDate.text = homework.entryDate.toFormattedString() + homeworkDialogSubject.text = homework.subject + homeworkDialogTeacher.text = homework.teacher + homeworkDialogContent.movementMethod = LinkMovementMethod.getInstance() + homeworkDialogContent.text = homework.content + homeworkDialogAttachments.movementMethod = LinkMovementMethod.getInstance() + homeworkDialogAttachments.text = HtmlCompat.fromHtml(homework.attachments.joinToString("
") { + "
${it.second}" + }, HtmlCompat.FROM_HTML_MODE_COMPACT).ifBlank { getString(R.string.all_no_data) } + + homeworkDialogRead.text = view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done) + homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) } + homeworkDialogClose.setOnClickListener { dismiss() } + } + + override fun updateMarkAsDoneLabel(isDone: Boolean) { + (parentFragment as? HomeworkFragment)?.onReloadList() + homeworkDialogRead.text = view?.context?.getString(if (isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done) + } + + override fun onDestroyView() { + presenter.onDetachView() + super.onDestroyView() + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsPresenter.kt new file mode 100644 index 000000000..04a97b8cd --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsPresenter.kt @@ -0,0 +1,44 @@ +package io.github.wulkanowy.ui.modules.homework.details + +import io.github.wulkanowy.data.db.entities.Homework +import io.github.wulkanowy.data.repositories.homework.HomeworkRepository +import io.github.wulkanowy.data.repositories.student.StudentRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.ui.base.ErrorHandler +import io.github.wulkanowy.utils.FirebaseAnalyticsHelper +import io.github.wulkanowy.utils.SchedulersProvider +import timber.log.Timber +import javax.inject.Inject + +class HomeworkDetailsPresenter @Inject constructor( + schedulers: SchedulersProvider, + errorHandler: ErrorHandler, + studentRepository: StudentRepository, + private val homeworkRepository: HomeworkRepository, + private val analytics: FirebaseAnalyticsHelper +) : BasePresenter(errorHandler, studentRepository, schedulers) { + + override fun onAttachView(view: HomeworkDetailsView) { + super.onAttachView(view) + view.initView() + Timber.i("Homework details view was initialized") + } + + fun toggleDone(homework: Homework) { + Timber.i("Homework details update start") + disposable.add(homeworkRepository.toggleDone(homework) + .subscribeOn(schedulers.backgroundThread) + .observeOn(schedulers.mainThread) + .subscribe({ + Timber.i("Homework details update: Success") + view?.run { + updateMarkAsDoneLabel(homework.isDone) + } + analytics.logEvent("homework_mark_as_done") + }) { + Timber.i("Homework details update result: An exception occurred") + errorHandler.dispatch(it) + } + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsView.kt new file mode 100644 index 000000000..697f22335 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsView.kt @@ -0,0 +1,10 @@ +package io.github.wulkanowy.ui.modules.homework.details + +import io.github.wulkanowy.ui.base.BaseView + +interface HomeworkDetailsView : BaseView { + + fun initView() + + fun updateMarkAsDoneLabel(isDone: Boolean) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt index dbcba4306..e87e260f7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainModule.kt @@ -20,6 +20,7 @@ import io.github.wulkanowy.ui.modules.exam.ExamFragment import io.github.wulkanowy.ui.modules.grade.GradeFragment import io.github.wulkanowy.ui.modules.grade.GradeModule import io.github.wulkanowy.ui.modules.homework.HomeworkFragment +import io.github.wulkanowy.ui.modules.homework.details.HomeworkDetailsDialog import io.github.wulkanowy.ui.modules.luckynumber.LuckyNumberFragment import io.github.wulkanowy.ui.modules.message.MessageFragment import io.github.wulkanowy.ui.modules.message.MessageModule @@ -98,6 +99,10 @@ abstract class MainModule { @ContributesAndroidInjector abstract fun bindHomeworkFragment(): HomeworkFragment + @PerFragment + @ContributesAndroidInjector + abstract fun bindHomeworkDetailsDialog(): HomeworkDetailsDialog + @PerFragment @ContributesAndroidInjector abstract fun bindLuckyNumberFragment(): LuckyNumberFragment diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..3c728c59f --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/dialog_homework.xml b/app/src/main/res/layout/dialog_homework.xml index 7ed9b795b..f6d000495 100644 --- a/app/src/main/res/layout/dialog_homework.xml +++ b/app/src/main/res/layout/dialog_homework.xml @@ -1,5 +1,6 @@ @@ -97,13 +98,46 @@ android:textIsSelectable="true" android:textSize="12sp" /> - + android:layout_marginTop="10dp" + android:text="@string/homework_attachments" + android:textSize="17sp" /> + + + + + + + + + diff --git a/app/src/main/res/layout/item_homework.xml b/app/src/main/res/layout/item_homework.xml index 68169039d..62566e9c2 100644 --- a/app/src/main/res/layout/item_homework.xml +++ b/app/src/main/res/layout/item_homework.xml @@ -1,4 +1,5 @@ - + android:ellipsize="end" + android:singleLine="true" + android:textSize="16sp" + app:layout_constraintEnd_toStartOf="@+id/homeworkItemTeacher" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + tools:text="@tools:sample/lorem/random" /> - + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="@id/homeworkItemSubject" + app:layout_constraintTop_toBottomOf="@id/homeworkItemSubject" + tools:text="@tools:sample/lorem/random" /> + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6c9829818..431a61ae3 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -219,6 +219,9 @@ Keine Informationen über Hausaufgaben + Gemacht + Unvollständig + Anhänge diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 33981e8ee..5411f1b9b 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -244,6 +244,9 @@ Brak zadań domowych + Wykonane + Niewykonane + Załączniki diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7e7313425..d9cd27c45 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -240,6 +240,9 @@ Нет домашних заданий + сделанный + Не сделано + Вложения diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 522eb8729..932df91ac 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -241,6 +241,9 @@ Немає домашніх завдань + зроблений + Не зроблено + Вкладення diff --git a/app/src/main/res/values/api_hosts.xml b/app/src/main/res/values/api_hosts.xml index 71162dc10..0e6b2e9cd 100644 --- a/app/src/main/res/values/api_hosts.xml +++ b/app/src/main/res/values/api_hosts.xml @@ -28,6 +28,6 @@ lublin tarnow rzeszow - Default + powiatwulkanowy diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1cd5aad65..4c7e7ef05 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -227,6 +227,9 @@ No info about homework + Mark as done + Mark as undone + Attachments From bf61dd1bad5d840984e9578545b619703ca517f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 4 Apr 2020 20:57:50 +0200 Subject: [PATCH 32/61] Add more details in email template (#751) --- app/build.gradle | 2 +- .../ui/modules/about/AboutFragment.kt | 36 ++++++------------- .../modules/login/form/LoginFormFragment.kt | 16 ++++++--- .../modules/login/form/LoginFormPresenter.kt | 5 ++- .../ui/modules/login/form/LoginFormView.kt | 2 +- .../LoginStudentSelectFragment.kt | 15 +++++--- .../LoginStudentSelectPresenter.kt | 7 ++-- .../studentselect/LoginStudentSelectView.kt | 2 +- .../login/symbol/LoginSymbolFragment.kt | 16 ++++++--- .../login/symbol/LoginSymbolPresenter.kt | 9 +++-- .../modules/login/symbol/LoginSymbolView.kt | 2 +- .../wulkanowy/utils/ContextExtension.kt | 16 +++++---- .../main/res/layout/fragment_login_symbol.xml | 28 ++++++++++----- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 4 +-- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values/strings.xml | 6 ++-- 18 files changed, 101 insertions(+), 71 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 501620f71..580d069a7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,7 +128,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:bff34b1" + implementation "io.github.wulkanowy:sdk:0cf724a" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt index cb455d0a0..5a32ac837 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/about/AboutFragment.kt @@ -1,12 +1,6 @@ package io.github.wulkanowy.ui.modules.about -import android.content.Intent -import android.content.Intent.ACTION_SENDTO -import android.content.Intent.EXTRA_EMAIL -import android.content.Intent.EXTRA_SUBJECT -import android.content.Intent.EXTRA_TEXT import android.graphics.drawable.Drawable -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -23,6 +17,7 @@ import io.github.wulkanowy.ui.modules.main.MainActivity import io.github.wulkanowy.ui.modules.main.MainView import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.getCompatDrawable +import io.github.wulkanowy.utils.openEmailClient import io.github.wulkanowy.utils.openInternetBrowser import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.fragment_about.* @@ -124,26 +119,17 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView { } override fun openEmailClient() { - val intent = Intent(ACTION_SENDTO) - .apply { - data = Uri.parse("mailto:") - putExtra(EXTRA_EMAIL, arrayOf("wulkanowyinc@gmail.com")) - putExtra(EXTRA_SUBJECT, "Zgłoszenie błędu") - putExtra(EXTRA_TEXT, "Tu umieść treść zgłoszenia\n\n${"-".repeat(40)}\n " + - """ - Build: ${appInfo.versionCode} - SDK: ${appInfo.systemVersion} - Device: ${appInfo.systemManufacturer} ${appInfo.systemModel} - """.trimIndent()) + requireContext().openEmailClient( + chooserTitle = getString(R.string.about_feedback), + email = "wulkanowyinc@gmail.com", + subject = "Zgłoszenie błędu", + body = requireContext().getString(R.string.about_feedback_template, + "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName + ), + onActivityNotFound = { + requireContext().openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage) } - - context?.let { - if (intent.resolveActivity(it.packageManager) != null) { - startActivity(Intent.createChooser(intent, getString(R.string.about_feedback))) - } else { - it.openInternetBrowser("https://github.com/wulkanowy/wulkanowy/issues", ::showMessage) - } - } + ) } override fun openFaqPage() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index b79da3cca..999ec22ab 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -233,12 +233,18 @@ class LoginFormFragment : BaseFragment(), LoginFormView { } } - override fun openEmail() { + override fun openEmail(lastError: String) { context?.openEmailClient( - requireContext().getString(R.string.login_email_intent_title), - "wulkanowyinc@gmail.com", - requireContext().getString(R.string.login_email_subject), - requireContext().getString(R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), appInfo.versionName) + chooserTitle = requireContext().getString(R.string.login_email_intent_title), + email = "wulkanowyinc@gmail.com", + subject = requireContext().getString(R.string.login_email_subject), + body = requireContext().getString(R.string.login_email_text, + "${appInfo.systemManufacturer} ${appInfo.systemModel}", + appInfo.systemVersion.toString(), + appInfo.versionName, + "$formHostValue/$formSymbolValue", + lastError + ) ) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index 3ed40539d..e566d3d6b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -16,6 +16,8 @@ class LoginFormPresenter @Inject constructor( private val analytics: FirebaseAnalyticsHelper ) : BasePresenter(loginErrorHandler, studentRepository, schedulers) { + private var lastError: Throwable? = null + override fun onAttachView(view: LoginFormView) { super.onAttachView(view) view.run { @@ -109,6 +111,7 @@ class LoginFormPresenter @Inject constructor( Timber.i("Login result: An exception occurred") analytics.logEvent("registration_form", "success" to false, "students" to -1, "scrapperBaseUrl" to host, "error" to it.message.ifNullOrBlank { "No message" }) loginErrorHandler.dispatch(it) + lastError = it view?.showContact(true) })) } @@ -118,7 +121,7 @@ class LoginFormPresenter @Inject constructor( } fun onEmailClick() { - view?.openEmail() + view?.openEmail(lastError?.message.ifNullOrBlank { "none" }) } fun onRecoverClick() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt index 80cf58448..8e46f93fd 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt @@ -67,7 +67,7 @@ interface LoginFormView : BaseView { fun openFaqPage() - fun openEmail() + fun openEmail(lastError: String) fun openAdvancedLogin() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt index 8478f7ccf..9860af22f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectFragment.kt @@ -101,12 +101,17 @@ class LoginStudentSelectFragment : BaseFragment(), LoginStudentSelectView { context?.openInternetBrowser("https://discord.gg/vccAQBr", ::showMessage) } - override fun openEmail() { + override fun openEmail(lastError: String) { context?.openEmailClient( - requireContext().getString(R.string.login_email_intent_title), - "wulkanowyinc@gmail.com", - requireContext().getString(R.string.login_email_subject), - requireContext().getString(R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), appInfo.versionName) + chooserTitle = requireContext().getString(R.string.login_email_intent_title), + email = "wulkanowyinc@gmail.com", + subject = requireContext().getString(R.string.login_email_subject), + body = requireContext().getString(R.string.login_email_text, appInfo.systemModel, + appInfo.systemVersion.toString(), + appInfo.versionName, + "Select users to log in", + lastError + ) ) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt index 87acebf1e..82de5a887 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectPresenter.kt @@ -8,7 +8,6 @@ import io.github.wulkanowy.ui.modules.login.LoginErrorHandler import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.ifNullOrBlank -import io.reactivex.Single import timber.log.Timber import java.io.Serializable import javax.inject.Inject @@ -20,6 +19,8 @@ class LoginStudentSelectPresenter @Inject constructor( private val analytics: FirebaseAnalyticsHelper ) : BasePresenter(loginErrorHandler, studentRepository, schedulers) { + private var lastError: Throwable? = null + var students = emptyList() private var selectedStudents = mutableListOf() @@ -83,6 +84,7 @@ class LoginStudentSelectPresenter @Inject constructor( }) }, { errorHandler.dispatch(it) + lastError = it view?.updateData(students.map { student -> LoginStudentSelectItem(student, false) }) }) ) @@ -109,6 +111,7 @@ class LoginStudentSelectPresenter @Inject constructor( students.forEach { analytics.logEvent("registration_student_select", "success" to false, "scrapperBaseUrl" to it.scrapperBaseUrl, "symbol" to it.symbol, "error" to error.message.ifNullOrBlank { "No message" }) } Timber.i("Registration result: An exception occurred ") loginErrorHandler.dispatch(error) + lastError = error view?.apply { showProgress(false) showContent(true) @@ -122,6 +125,6 @@ class LoginStudentSelectPresenter @Inject constructor( } fun onEmailClick() { - view?.openEmail() + view?.openEmail(lastError?.message.ifNullOrBlank { "empty" }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt index 238771009..d80b059db 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/studentselect/LoginStudentSelectView.kt @@ -20,5 +20,5 @@ interface LoginStudentSelectView : BaseView { fun openDiscordInvite() - fun openEmail() + fun openEmail(lastError: String) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt index 5e9ce3ba3..5602b6248 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolFragment.kt @@ -130,12 +130,18 @@ class LoginSymbolFragment : BaseFragment(), LoginSymbolView { context?.openInternetBrowser("https://wulkanowy.github.io/czesto-zadawane-pytania/co-to-jest-symbol", ::showMessage) } - override fun openEmail() { + override fun openEmail(host: String, lastError: String) { context?.openEmailClient( - requireContext().getString(R.string.login_email_intent_title), - "wulkanowyinc@gmail.com", - requireContext().getString(R.string.login_email_subject), - requireContext().getString(R.string.login_email_text, appInfo.systemModel, appInfo.systemVersion.toString(), appInfo.versionName) + chooserTitle = requireContext().getString(R.string.login_email_intent_title), + email = "wulkanowyinc@gmail.com", + subject = requireContext().getString(R.string.login_email_subject), + body = requireContext().getString(R.string.login_email_text, + "${appInfo.systemManufacturer} ${appInfo.systemModel}", + appInfo.systemVersion.toString(), + appInfo.versionName, + "$host/${loginSymbolName.text}", + lastError + ) ) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt index ee6c30c3b..1f9e66b70 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolPresenter.kt @@ -18,6 +18,8 @@ class LoginSymbolPresenter @Inject constructor( private val analytics: FirebaseAnalyticsHelper ) : BasePresenter(loginErrorHandler, studentRepository, schedulers) { + private var lastError: Throwable? = null + var loginData: Triple? = null @Suppress("UNCHECKED_CAST") @@ -37,13 +39,15 @@ class LoginSymbolPresenter @Inject constructor( } fun attemptLogin(symbol: String) { + if (loginData == null) throw IllegalArgumentException("Login data is null") + if (symbol.isBlank()) { view?.setErrorSymbolRequire() return } disposable.add( - Single.fromCallable { if (loginData == null) throw IllegalArgumentException("Login data is null") else loginData } + Single.fromCallable { loginData } .flatMap { studentRepository.getStudentsScrapper(it.first, it.second, it.third, symbol) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) @@ -77,6 +81,7 @@ class LoginSymbolPresenter @Inject constructor( Timber.i("Login with symbol result: An exception occurred") analytics.logEvent("registration_symbol", "success" to false, "students" to -1, "scrapperBaseUrl" to loginData?.third, "symbol" to symbol, "error" to it.message.ifNullOrBlank { "No message" }) loginErrorHandler.dispatch(it) + lastError = it view?.showContact(true) })) } @@ -94,6 +99,6 @@ class LoginSymbolPresenter @Inject constructor( } fun onEmailClick() { - view?.openEmail() + view?.openEmail(loginData?.third.orEmpty(), lastError?.message.ifNullOrBlank { "empty" }) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt index 1afc15327..6938bf138 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/symbol/LoginSymbolView.kt @@ -31,5 +31,5 @@ interface LoginSymbolView : BaseView { fun openFaqPage() - fun openEmail() + fun openEmail(host: String, lastError: String) } diff --git a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt index a265378e2..582b1c835 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/ContextExtension.kt @@ -32,12 +32,16 @@ fun Context.openInternetBrowser(uri: String, onActivityNotFound: (uri: String) - } } -fun Context.openEmailClient(chooserTitle: String, email: String, subject: String?, body: String?) { - val emailIntent = Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", email, null)) - emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(email)) - if (subject != null) emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject) - if (body != null) emailIntent.putExtra(Intent.EXTRA_TEXT, body) - startActivity(Intent.createChooser(emailIntent, chooserTitle)) +fun Context.openEmailClient(chooserTitle: String, email: String, subject: String, body: String, onActivityNotFound: () -> Unit = {}) { + val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:")).apply { + putExtra(Intent.EXTRA_EMAIL, arrayOf(email)) + putExtra(Intent.EXTRA_SUBJECT, subject) + putExtra(Intent.EXTRA_TEXT, body) + } + + if (intent.resolveActivity(packageManager) != null) { + startActivity(Intent.createChooser(intent, chooserTitle)) + } else onActivityNotFound() } fun Context.openNavigation(location: String) { diff --git a/app/src/main/res/layout/fragment_login_symbol.xml b/app/src/main/res/layout/fragment_login_symbol.xml index 56b4a32e5..77f44d213 100644 --- a/app/src/main/res/layout/fragment_login_symbol.xml +++ b/app/src/main/res/layout/fragment_login_symbol.xml @@ -108,31 +108,41 @@ android:text="@string/login_header_symbol" android:textSize="16sp" app:fontFamily="sans-serif-light" - app:layout_constraintBottom_toTopOf="@+id/loginSymbolNameLayout" + app:layout_constraintBottom_toTopOf="@+id/loginSymbolHelper" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginSymbolContact" app:layout_constraintVertical_chainStyle="packed" /> + + + app:layout_constraintTop_toBottomOf="@+id/loginSymbolHelper"> Student nicht gefunden. Überprüfen Sie das Symbol Dieses Datenfeld ist erforderlich Ausgewählter Student ist bereits angemeldet. - Das Symbol finden Sie auf der Registerseite unter Uczeń -> Dostęp Mobilny -> Zarejestruj urządzenie mobilne + Das Symbol finden Sie auf der Registerseite unter Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne Wählen Sie die Studenten aus, die sich bei der Anwendung anmelden sollen. Andere Optionen Datenschutzerklärung diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 5411f1b9b..4d2c7c458 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -44,7 +44,7 @@ Klucz API Zaloguj To hasło jest za krótkie - Dane logowania są niepoprawne. Upewnij się, że został wybrany odpowiedni dziennik UONET+ + Dane logowania są niepoprawne. Upewnij się, że został wybrany odpowiedni dziennik UONET+ w polu poniżej Nieprawidłowy PIN Nieprawidłowy token Token stracił ważność @@ -54,7 +54,7 @@ Nie znaleziono ucznia. Sprawdź symbol To pole jest wymagane Wybrany uczeń jest już zalogowany - Symbol znajdziesz na stronie dziennika w Uczeń -> Dostęp Mobilny -> Zarejestruj urządzenie mobilne + Symbol znajdziesz na stronie dziennika w Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne Wybierz uczniów do zalogowania w aplikacji Inne opcje W tym trybie nie działa szczęśliwy numerek, uczeń na tle klasy, podsumowanie frekwencji, usprawiedliwianie nieobecności, lekcje zrealizowane, informacje o szkole i podgląd listy zarejestrowanych urządzeń diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index d9cd27c45..a13db9fd2 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -54,7 +54,7 @@ Не удалось найти ученика. Пожалуйста, проверьте \"symbol\" Это поле обязательно Данный ученик уже авторизован - Вы можете найти \"symbol\" в Uczeń -> Dostęp Mobilny -> Zarejestruj urządzenie mobilne + Вы можете найти \"symbol\" в Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne Выберите учеников для авторизации в приложении Другие варианты Политика приватности diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 932df91ac..913461f80 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -55,7 +55,7 @@ Не вдалося знайти учня. Будь ласка, перевірте \"symbol\" Це поле обов\'язкове Даний учень вже авторизований - Ви можете знайти \"symbol\" в Uczeń -> Dostęp Mobilny -> Zarejestruj urządzenie mobilne + Ви можете знайти \"symbol\" в Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne Виберіть учнів для авторизації в додатку Інші варіанти Політика приватності diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4c7e7ef05..f3aa468af 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -55,7 +55,7 @@ Student not found. Check the symbol This field is required Selected student is already logged in - The symbol can be found on the register page in Uczeń -> Dostęp Mobilny -> Zarejestruj urządzenie mobilne + The symbol can be found on the register page in Uczeń → Dostęp Mobilny → Zarejestruj urządzenie mobilne Select students to log in to the application Other options In this mode, a lucky number does not work, a class grade stats, summary of attendance, excuse for absence, completed lessons, school information and preview of the list of registered devices @@ -66,8 +66,9 @@ Email Discord Send email + Describe details of problem: Zgłoszenie: Problemy z logowaniem - Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\n\nOpis problemu: + Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\nDodatkowe informacje: %4$s\nOstatni błąd: %5$s\n\nOpis problemu: Make sure the correct UONET+ register is selected! I forgot my password Recover your account @@ -295,6 +296,7 @@ Visit the website and help develop the application Licenses Licenses of libraries used in the application + Informacje o aplikacji:\n\nUrządzenie: %1$s\nWersja SDK: %2$s\nWersja aplikacji: %3$s\n\nTreść zgłoszenia: From 36123266286dbf64dce803204f156b3bed5bc81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sat, 4 Apr 2020 20:59:44 +0200 Subject: [PATCH 33/61] Add missing sdk initialization in lucky number repository (#752) --- .../luckynumber/LuckyNumberRepository.kt | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt index 374b9a294..0ea063501 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt @@ -2,6 +2,7 @@ package io.github.wulkanowy.data.repositories.luckynumber import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings +import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.Student import io.reactivex.Completable @@ -15,33 +16,36 @@ import javax.inject.Singleton class LuckyNumberRepository @Inject constructor( private val settings: InternetObservingSettings, private val local: LuckyNumberLocal, - private val remote: LuckyNumberRemote + private val remote: LuckyNumberRemote, + private val sdkHelper: SdkHelper ) { fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe { - return local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMapMaybe { - if (it) remote.getLuckyNumber(student) - else Maybe.error(UnknownHostException()) - }.flatMap { new -> - local.getLuckyNumber(student, LocalDate.now()) - .doOnSuccess { old -> - if (new != old) { - local.deleteLuckyNumber(old) + return Maybe.just(sdkHelper.init(student)).flatMap { + local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMapMaybe { + if (it) remote.getLuckyNumber(student) + else Maybe.error(UnknownHostException()) + }.flatMap { new -> + local.getLuckyNumber(student, LocalDate.now()) + .doOnSuccess { old -> + if (new != old) { + local.deleteLuckyNumber(old) + local.saveLuckyNumber(new.apply { + if (notify) isNotified = false + }) + } + } + .doOnComplete { local.saveLuckyNumber(new.apply { if (notify) isNotified = false }) } - } - .doOnComplete { - local.saveLuckyNumber(new.apply { - if (notify) isNotified = false - }) - } - }.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) }, - { local.getLuckyNumber(student, LocalDate.now()) }) - ) + }.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) }, + { local.getLuckyNumber(student, LocalDate.now()) }) + ) + } } fun getNotNotifiedLuckyNumber(student: Student): Maybe { From 6a0ce3a58d2d95dbce60ed51a38fc98396953d45 Mon Sep 17 00:00:00 2001 From: Dominik Korsa Date: Sun, 5 Apr 2020 16:46:49 +0200 Subject: [PATCH 34/61] Add force sync feature in settings (#643) --- app/build.gradle | 2 ++ .../wulkanowy/services/sync/SyncManager.kt | 23 +++++++++++-- .../wulkanowy/services/sync/SyncWorker.kt | 19 ++++++++--- .../ui/modules/main/MainPresenter.kt | 2 +- .../ui/modules/settings/SettingsFragment.kt | 32 ++++++++++++++++++- .../ui/modules/settings/SettingsPresenter.kt | 27 ++++++++++++++-- .../ui/modules/settings/SettingsView.kt | 10 ++++++ app/src/main/res/values-pl/strings.xml | 9 ++++++ app/src/main/res/values/preferences_keys.xml | 1 + app/src/main/res/values/strings.xml | 9 ++++++ app/src/main/res/xml/scheme_preferences.xml | 4 +++ 11 files changed, 128 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 580d069a7..2b4c6818c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -154,6 +154,8 @@ dependencies { implementation "androidx.work:work-rxjava2:$work_manager" implementation "androidx.work:work-gcm:$work_manager" + implementation 'com.github.PaulinaSadowska:RxWorkManagerObservers:1.0.0' + implementation "androidx.room:room-runtime:$room" implementation "androidx.room:room-rxjava2:$room" implementation "androidx.room:room-ktx:$room" diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt b/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt index 3d0cbcf63..dda2abe0c 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncManager.kt @@ -5,18 +5,24 @@ import android.os.Build.VERSION_CODES.O import androidx.core.app.NotificationManagerCompat import androidx.work.BackoffPolicy.EXPONENTIAL import androidx.work.Constraints +import androidx.work.Data import androidx.work.ExistingPeriodicWorkPolicy.KEEP import androidx.work.ExistingPeriodicWorkPolicy.REPLACE +import androidx.work.ExistingWorkPolicy import androidx.work.NetworkType.CONNECTED import androidx.work.NetworkType.UNMETERED +import androidx.work.OneTimeWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkInfo import androidx.work.WorkManager +import com.paulinasadowska.rxworkmanagerobservers.extensions.getWorkInfoByIdObservable import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.services.sync.channels.Channel import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.isHolidays +import io.reactivex.Observable import org.threeten.bp.LocalDate.now import timber.log.Timber import java.util.concurrent.TimeUnit.MINUTES @@ -42,13 +48,13 @@ class SyncManager @Inject constructor( } if (sharedPrefProvider.getLong(APP_VERSION_CODE_KEY, -1L) != appInfo.versionCode.toLong()) { - startSyncWorker(true) + startPeriodicSyncWorker(true) sharedPrefProvider.putLong(APP_VERSION_CODE_KEY, appInfo.versionCode.toLong(), true) } Timber.i("SyncManager was initialized") } - fun startSyncWorker(restart: Boolean = false) { + fun startPeriodicSyncWorker(restart: Boolean = false) { if (preferencesRepository.isServiceEnabled && !now().isHolidays) { workManager.enqueueUniquePeriodicWork(SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP, PeriodicWorkRequestBuilder(preferencesRepository.servicesInterval, MINUTES) @@ -61,6 +67,19 @@ class SyncManager @Inject constructor( } } + fun startOneTimeSyncWorker(): Observable { + val work = OneTimeWorkRequestBuilder() + .setInputData( + Data.Builder() + .putBoolean("one_time", true) + .build() + ) + .build() + + workManager.enqueueUniqueWork("${SyncWorker::class.java.simpleName}_one_time", ExistingWorkPolicy.REPLACE, work) + return workManager.getWorkInfoByIdObservable(work.id) + } + fun stopSyncWorker() { workManager.cancelUniqueWork(SyncWorker::class.java.simpleName) } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt index 68702d9a9..8a38fa557 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/SyncWorker.kt @@ -1,10 +1,12 @@ package io.github.wulkanowy.services.sync import android.content.Context +import android.os.Build.VERSION_CODES.LOLLIPOP import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat.BigTextStyle import androidx.core.app.NotificationCompat.PRIORITY_DEFAULT import androidx.core.app.NotificationManagerCompat +import androidx.work.Data import androidx.work.ListenableWorker import androidx.work.RxWorker import androidx.work.WorkerParameters @@ -17,6 +19,7 @@ import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.sdk.exception.FeatureDisabledException import io.github.wulkanowy.services.sync.channels.DebugChannel import io.github.wulkanowy.services.sync.works.Work +import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.getCompatColor import io.reactivex.Completable import io.reactivex.Single @@ -30,7 +33,8 @@ class SyncWorker @AssistedInject constructor( private val semesterRepository: SemesterRepository, private val works: Set<@JvmSuppressWildcards Work>, private val preferencesRepository: PreferencesRepository, - private val notificationManager: NotificationManagerCompat + private val notificationManager: NotificationManagerCompat, + private val appInfo: AppInfo ) : RxWorker(appContext, workerParameters) { override fun createWork(): Single { @@ -52,8 +56,15 @@ class SyncWorker @AssistedInject constructor( .toSingleDefault(Result.success()) .onErrorReturn { Timber.e(it, "There was an error during synchronization") - if (it is FeatureDisabledException) Result.success() - else Result.retry() + when { + it is FeatureDisabledException -> Result.success() + inputData.getBoolean("one_time", false) -> { + Result.failure(Data.Builder() + .putString("error", it.toString()) + .build()) + } + else -> Result.retry() + } } .doOnSuccess { if (preferencesRepository.isDebugNotificationEnable) notify(it) @@ -64,7 +75,7 @@ class SyncWorker @AssistedInject constructor( private fun notify(result: Result) { notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(applicationContext, DebugChannel.CHANNEL_ID) .setContentTitle("Debug notification") - .setSmallIcon(R.drawable.ic_more_settings) + .setSmallIcon(R.drawable.ic_stat_push) .setAutoCancel(true) .setColor(applicationContext.getCompatColor(R.color.colorPrimary)) .setStyle(BigTextStyle().bigText("${SyncWorker::class.java.simpleName} result: $result")) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt index e6c299171..f5a490044 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainPresenter.kt @@ -33,7 +33,7 @@ class MainPresenter @Inject constructor( Timber.i("Main view was initialized with $startMenuIndex menu index and $startMenuMoreIndex more index") } - syncManager.startSyncWorker() + syncManager.startPeriodicSyncWorker() analytics.logEvent("app_open", "destination" to initMenu?.name) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt index 03a89d274..5a8593a06 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.settings import android.content.Context import android.content.SharedPreferences import android.os.Bundle +import androidx.appcompat.app.AlertDialog import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.yariksoffice.lingver.Lingver @@ -33,11 +34,24 @@ class SettingsFragment : PreferenceFragmentCompat(), override val titleStringId get() = R.string.settings_title + override val syncSuccessString get() = getString(R.string.pref_services_message_sync_success) + + override val syncFailedString get() = getString(R.string.pref_services_message_sync_failed) + override fun onAttach(context: Context) { AndroidSupportInjection.inject(this) super.onAttach(context) } + override fun initView() { + findPreference(getString(R.string.pref_key_services_force_sync))?.run { + onPreferenceClickListener = Preference.OnPreferenceClickListener { + presenter.onSyncNowClicked() + true + } + } + } + override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) presenter.onAttachView(this) @@ -61,12 +75,19 @@ class SettingsFragment : PreferenceFragmentCompat(), } override fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) { - findPreference(serviceEnablesKey)?.apply { + findPreference(serviceEnablesKey)?.run { summary = if (isHolidays) getString(R.string.pref_services_suspended) else "" isEnabled = !isHolidays } } + override fun setSyncInProgress(inProgress: Boolean) { + findPreference(getString(R.string.pref_key_services_force_sync))?.run { + isEnabled = !inProgress + summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else "" + } + } + override fun showError(text: String, error: Throwable) { (activity as? BaseActivity<*>)?.showError(text, error) } @@ -87,6 +108,15 @@ class SettingsFragment : PreferenceFragmentCompat(), ErrorDialog.newInstance(error).show(childFragmentManager, error.toString()) } + override fun showForceSyncDialog() { + AlertDialog.Builder(requireContext()) + .setTitle(R.string.pref_services_dialog_force_sync_title) + .setMessage(R.string.pref_services_dialog_force_sync_summary) + .setPositiveButton(android.R.string.ok) { _, _ -> presenter.onForceSyncDialogSubmit() } + .setNegativeButton(android.R.string.cancel) { _, _ -> } + .show() + } + override fun onResume() { super.onResume() preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index 3f2bf714c..ce5100ea8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -1,5 +1,6 @@ package io.github.wulkanowy.ui.modules.settings +import androidx.work.WorkInfo import com.chuckerteam.chucker.api.ChuckerCollector import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.student.StudentRepository @@ -29,6 +30,7 @@ class SettingsPresenter @Inject constructor( super.onAttachView(view) Timber.i("Settings view was initialized") view.setServicesSuspended(preferencesRepository.serviceEnableKey, now().isHolidays) + view.initView() } fun onSharedPreferenceChanged(key: String) { @@ -36,8 +38,8 @@ class SettingsPresenter @Inject constructor( with(preferencesRepository) { when (key) { - serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() } - servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true) + serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startPeriodicSyncWorker() else stopSyncWorker() } + servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startPeriodicSyncWorker(true) isDebugNotificationEnableKey -> chuckerCollector.showNotification = isDebugNotificationEnable appThemeKey -> view?.recreateView() appLanguageKey -> view?.run { @@ -49,4 +51,25 @@ class SettingsPresenter @Inject constructor( } analytics.logEvent("setting_changed", "name" to key) } + + fun onSyncNowClicked() { + view?.showForceSyncDialog() + } + + fun onForceSyncDialogSubmit() { + view?.run { + Timber.i("Setting sync now started") + analytics.logEvent("sync_now_started") + disposable.add(syncManager.startOneTimeSyncWorker() + .doOnSubscribe { setSyncInProgress(true) } + .doFinally { setSyncInProgress(false) } + .subscribe({ workInfo -> + if (workInfo.state == WorkInfo.State.SUCCEEDED) showMessage(syncSuccessString) + else if (workInfo.state == WorkInfo.State.FAILED) showError(syncFailedString, Throwable(workInfo.outputData.getString("error"))) + }, { + Timber.e("Sync now failed") + }) + ) + } + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt index e50eb47b3..4a1b0c766 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsView.kt @@ -4,9 +4,19 @@ import io.github.wulkanowy.ui.base.BaseView interface SettingsView : BaseView { + val syncSuccessString: String + + val syncFailedString: String + + fun initView() + fun recreateView() fun updateLanguage(langCode: String) fun setServicesSuspended(serviceEnablesKey: String, isHolidays: Boolean) + + fun setSyncInProgress(inProgress: Boolean) + + fun showForceSyncDialog() } diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 4d2c7c458..cbdf94e39 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -375,6 +375,15 @@ Zawieszona na wakacjach Interwał aktualizacji Tylko WiFi + Synchronizuj teraz + Zsynchronizowano! + Synchronizacja nie powiodła się + Synchronizacja w trakcie + Synchronizacja + + Ręczna synchronizacja nie odświeża widoków w aplikacji. + \nAby zobaczyć zsynchronizowane informacje uruchom ponownie aplikację po zsynchronizowaniu. + Inne Wartość plusa diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml index 49601b550..559e2159c 100644 --- a/app/src/main/res/values/preferences_keys.xml +++ b/app/src/main/res/values/preferences_keys.xml @@ -11,6 +11,7 @@ services_enable services_interval services_disable_wifi_only + services_force_sync notifications_enable notification_debug grade_modifier_plus diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f3aa468af..a3384c74d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -360,6 +360,15 @@ Suspended on holidays Updates interval Wi-Fi only + Sync now + Synced! + Sync failed + Sync in progress + Synchronization + + Manual sync doesn\'t refresh app views. + \nTo see the synced data relaunch the app after syncing. + Other Value of the plus diff --git a/app/src/main/res/xml/scheme_preferences.xml b/app/src/main/res/xml/scheme_preferences.xml index e92aca63f..bb9eb5fcd 100644 --- a/app/src/main/res/xml/scheme_preferences.xml +++ b/app/src/main/res/xml/scheme_preferences.xml @@ -77,6 +77,10 @@ app:iconSpaceReserved="false" app:key="@string/pref_key_services_wifi_only" app:title="@string/pref_services_wifi" /> + Date: Sun, 5 Apr 2020 15:32:18 +0000 Subject: [PATCH 35/61] Bump threetenbp from 1.4.2 to 1.4.3 (#756) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 2b4c6818c..9857af1ed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -200,7 +200,7 @@ dependencies { testImplementation "junit:junit:4.13" testImplementation "io.mockk:mockk:$mockk" - testImplementation "org.threeten:threetenbp:1.4.2" + testImplementation "org.threeten:threetenbp:1.4.3" testImplementation "org.mockito:mockito-inline:3.3.3" androidTestImplementation "androidx.test:core:1.2.0" From c9b35bed7eb5dc48bd06832675cf293ab429e491 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2020 16:22:50 +0000 Subject: [PATCH 36/61] Bump chucker from 3.1.1 to 3.2.0 (#755) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 9857af1ed..67f3362b6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -119,7 +119,7 @@ ext { room = "2.2.5" dagger = "2.27" // don't update https://github.com/ChuckerTeam/chucker/issues/242 - chucker = "3.1.1" + chucker = "3.2.0" mockk = "1.9.2" } From bb30cf2ce30a5c47042dd563a3d43cf7dfba9133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 5 Apr 2020 18:32:57 +0200 Subject: [PATCH 37/61] Revert "Add "System theme" option to widgets" (#753) --- .../LuckyNumberWidgetConfigureActivity.kt | 17 ++++------------- .../TimetableWidgetConfigureActivity.kt | 13 ++----------- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-uk/strings.xml | 1 - app/src/main/res/values/strings.xml | 1 - 7 files changed, 6 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt index 056a15270..e8ce3bcfb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/luckynumberwidget/LuckyNumberWidgetConfigureActivity.kt @@ -4,9 +4,6 @@ import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS import android.content.Intent -import android.content.res.Configuration -import android.content.res.Configuration.UI_MODE_NIGHT_YES -import android.os.Build import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AlertDialog @@ -16,7 +13,6 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.login.LoginActivity -import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.activity_widget_configure.* import javax.inject.Inject @@ -30,9 +26,6 @@ class LuckyNumberWidgetConfigureActivity : BaseActivity= Build.VERSION_CODES.Q) items+=(getString(R.string.widget_timetable_theme_system)) - dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher) + dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher) .setTitle(R.string.widget_timetable_theme_title) - .setOnDismissListener { presenter.onDismissThemeView() } + .setOnDismissListener { presenter.onDismissThemeView() } .setSingleChoiceItems(items, -1) { _, which -> - val isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES - presenter.onThemeSelect(if (isDarkMode && which == 2 || which == 1) 1 else 0) + presenter.onThemeSelect(which) } .show() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt index 112092816..7636637f4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetConfigureActivity.kt @@ -4,9 +4,6 @@ import android.appwidget.AppWidgetManager.ACTION_APPWIDGET_UPDATE import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_IDS import android.content.Intent -import android.content.res.Configuration -import android.content.res.Configuration.UI_MODE_NIGHT_YES -import android.os.Build import android.os.Bundle import android.widget.Toast import android.widget.Toast.LENGTH_LONG @@ -18,7 +15,6 @@ import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseActivity import io.github.wulkanowy.ui.modules.login.LoginActivity import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetProvider.Companion.EXTRA_FROM_PROVIDER -import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.setOnItemClickListener import kotlinx.android.synthetic.main.activity_widget_configure.* import javax.inject.Inject @@ -32,9 +28,6 @@ class TimetableWidgetConfigureActivity : BaseActivity= Build.VERSION_CODES.Q) items += getString(R.string.widget_timetable_theme_system) dialog = AlertDialog.Builder(this, R.style.WulkanowyTheme_WidgetAccountSwitcher) .setTitle(R.string.widget_timetable_theme_title) .setOnDismissListener { presenter.onDismissThemeView() } .setSingleChoiceItems(items, -1) { _, which -> - val isDarkMode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES - presenter.onThemeSelect(if (isDarkMode && which == 2 || which == 1) 1 else 0) + presenter.onThemeSelect(which) } .show() } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index a279bd380..1608d2c93 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -326,7 +326,6 @@ Thema wählen Licht Dunkel - Systemthema diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index cbdf94e39..9cd652723 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -351,7 +351,6 @@ Wybierz motyw Jasny Ciemny - Motyw systemu diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a13db9fd2..e637e3ea9 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -348,7 +348,6 @@ Выбрать тему Светлая Тёмная - Системная тема diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 913461f80..9caf13a6b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -349,7 +349,6 @@ Вибрати тему Світла Темна - Тема системи diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a3384c74d..ae1627ae5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -336,7 +336,6 @@ Choose theme Light Dark - System Theme From 4833e1e130af8d6103aec8b4e21137ca58ac15fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 5 Apr 2020 18:35:00 +0200 Subject: [PATCH 38/61] Version 0.17.0 --- .travis.yml | 2 +- app/build.gradle | 6 +++--- app/src/main/play/release-notes/pl-PL/default.txt | 15 ++++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc45f7dbe..a5cb2ed91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ cache: branches: only: - develop - - 0.16.0 + - 0.17.0 android: licenses: diff --git a/app/build.gradle b/app/build.gradle index 67f3362b6..9eeb3e7d9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 17 targetSdkVersion 29 - versionCode 53 - versionName "0.16.0" + versionCode 54 + versionName "0.17.0" multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true @@ -128,7 +128,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:0cf724a" + implementation "io.github.wulkanowy:sdk:0.17.0" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/src/main/play/release-notes/pl-PL/default.txt b/app/src/main/play/release-notes/pl-PL/default.txt index be1a02e7f..64aa622c8 100644 --- a/app/src/main/play/release-notes/pl-PL/default.txt +++ b/app/src/main/play/release-notes/pl-PL/default.txt @@ -1,10 +1,11 @@ -Wersja 0.16.0 +Wersja 0.17.0 -- oceny zapisane w nawiasach nie są już liczone do średniej -- naprawiliśmy wyświetlanie szczęśliwych numerków na kontach rodziców (może być potrzebne zalogowanie się ponownie) -- dodaliśmy opcję przywracania hasła, ulepszyliśmy formularz logowania -- dodaliśmy język ukraiński i niemiecki -- dodaliśmy informację na górnym pasku o bieżącym semestrze w widoku ocen -- ulepszyliśmy przełączanie aplikacji na nowy semestr +- dodaliśmy wsparcie dla załączników w wiadomosciach i zadaniach domowych +- dodaliśmy oznaczanie zadań domowych jako wykonanych +- dodaliśmy wyświetlanie punktów przy uwagach +- dodaliśmy funkcję powiadomień o awariach dziennika +- dodaliśmy funkcję wymuszenia pełnej synchronizacji +- zmieniliśmy sposób zwracania się do użytkownika na bezosobowy +- naprawiliśmy logowanie na androidach niższych niż 5.0 Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases From 0a18fefb1f149604f5e1ebada57d4854c44be07c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 8 Apr 2020 18:17:20 +0200 Subject: [PATCH 39/61] Use recycler view in homework details dialog (#761) --- .../details/HomeworkDetailsAdapter.kt | 84 +++++++++ .../homework/details/HomeworkDetailsDialog.kt | 27 ++- app/src/main/res/layout/dialog_homework.xml | 168 ++++-------------- .../item_homework_dialog_attachment.xml | 21 +++ ...tem_homework_dialog_attachments_header.xml | 14 ++ .../layout/item_homework_dialog_details.xml | 96 ++++++++++ 6 files changed, 260 insertions(+), 150 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsAdapter.kt create mode 100644 app/src/main/res/layout/item_homework_dialog_attachment.xml create mode 100644 app/src/main/res/layout/item_homework_dialog_attachments_header.xml create mode 100644 app/src/main/res/layout/item_homework_dialog_details.xml diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsAdapter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsAdapter.kt new file mode 100644 index 000000000..3706b56e1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsAdapter.kt @@ -0,0 +1,84 @@ +package io.github.wulkanowy.ui.modules.homework.details + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Homework +import io.github.wulkanowy.utils.toFormattedString +import kotlinx.android.synthetic.main.item_homework_dialog_attachment.view.* +import kotlinx.android.synthetic.main.item_homework_dialog_details.view.* +import javax.inject.Inject + +class HomeworkDetailsAdapter @Inject constructor() : + RecyclerView.Adapter() { + + private enum class ViewType(val id: Int) { + DETAILS(1), + ATTACHMENTS_HEADER(2), + ATTACHMENT(3) + } + + private var attachments = emptyList>() + + var homework: Homework? = null + set(value) { + field = value + attachments = value?.attachments.orEmpty() + } + + var onAttachmentClickListener: (url: String) -> Unit = {} + + override fun getItemCount() = 1 + if (attachments.isNotEmpty()) attachments.size + 1 else 0 + + override fun getItemViewType(position: Int) = when (position) { + 0 -> ViewType.DETAILS.id + 1 -> ViewType.ATTACHMENTS_HEADER.id + else -> ViewType.ATTACHMENT.id + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + + return when (viewType) { + ViewType.ATTACHMENTS_HEADER.id -> AttachmentsHeaderViewHolder(inflater.inflate(R.layout.item_homework_dialog_attachments_header, parent, false)) + ViewType.ATTACHMENT.id -> AttachmentViewHolder(inflater.inflate(R.layout.item_homework_dialog_attachment, parent, false)) + else -> DetailsViewHolder(inflater.inflate(R.layout.item_homework_dialog_details, parent, false)) + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is DetailsViewHolder -> bindDetailsViewHolder(holder) + is AttachmentViewHolder -> bindAttachmentViewHolder(holder, position - 2) + } + } + + private fun bindDetailsViewHolder(holder: DetailsViewHolder) { + with(holder.view) { + homeworkDialogDate.text = homework?.date?.toFormattedString() + homeworkDialogEntryDate.text = homework?.entryDate?.toFormattedString() + homeworkDialogSubject.text = homework?.subject + homeworkDialogTeacher.text = homework?.teacher + homeworkDialogContent.text = homework?.content + } + } + + private fun bindAttachmentViewHolder(holder: AttachmentViewHolder, position: Int) { + val item = attachments[position] + + with(holder.view) { + homeworkDialogAttachment.text = item.second + setOnClickListener { + onAttachmentClickListener(item.first) + } + } + } + + class DetailsViewHolder(val view: View) : RecyclerView.ViewHolder(view) + + class AttachmentsHeaderViewHolder(val view: View) : RecyclerView.ViewHolder(view) + + class AttachmentViewHolder(val view: View) : RecyclerView.ViewHolder(view) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt index 58622848e..54cb5c68c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/details/HomeworkDetailsDialog.kt @@ -2,16 +2,15 @@ package io.github.wulkanowy.ui.modules.homework.details import android.annotation.SuppressLint import android.os.Bundle -import android.text.method.LinkMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.text.HtmlCompat +import androidx.recyclerview.widget.LinearLayoutManager import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.ui.base.BaseDialogFragment import io.github.wulkanowy.ui.modules.homework.HomeworkFragment -import io.github.wulkanowy.utils.toFormattedString +import io.github.wulkanowy.utils.openInternetBrowser import kotlinx.android.synthetic.main.dialog_homework.* import javax.inject.Inject @@ -20,6 +19,9 @@ class HomeworkDetailsDialog : BaseDialogFragment(), HomeworkDetailsView { @Inject lateinit var presenter: HomeworkDetailsPresenter + @Inject + lateinit var detailsAdapter: HomeworkDetailsAdapter + private lateinit var homework: Homework companion object { @@ -51,20 +53,17 @@ class HomeworkDetailsDialog : BaseDialogFragment(), HomeworkDetailsView { @SuppressLint("SetTextI18n") override fun initView() { - homeworkDialogDate.text = homework.date.toFormattedString() - homeworkDialogEntryDate.text = homework.entryDate.toFormattedString() - homeworkDialogSubject.text = homework.subject - homeworkDialogTeacher.text = homework.teacher - homeworkDialogContent.movementMethod = LinkMovementMethod.getInstance() - homeworkDialogContent.text = homework.content - homeworkDialogAttachments.movementMethod = LinkMovementMethod.getInstance() - homeworkDialogAttachments.text = HtmlCompat.fromHtml(homework.attachments.joinToString("
") { - "${it.second}" - }, HtmlCompat.FROM_HTML_MODE_COMPACT).ifBlank { getString(R.string.all_no_data) } - homeworkDialogRead.text = view?.context?.getString(if (homework.isDone) R.string.homework_mark_as_undone else R.string.homework_mark_as_done) homeworkDialogRead.setOnClickListener { presenter.toggleDone(homework) } homeworkDialogClose.setOnClickListener { dismiss() } + + with(homeworkDialogRecycler) { + layoutManager = LinearLayoutManager(context) + adapter = detailsAdapter.apply { + onAttachmentClickListener = { context.openInternetBrowser(it, ::showMessage) } + homework = this@HomeworkDetailsDialog.homework + } + } } override fun updateMarkAsDoneLabel(isDone: Boolean) { diff --git a/app/src/main/res/layout/dialog_homework.xml b/app/src/main/res/layout/dialog_homework.xml index f6d000495..a2c2ec470 100644 --- a/app/src/main/res/layout/dialog_homework.xml +++ b/app/src/main/res/layout/dialog_homework.xml @@ -1,143 +1,39 @@ - - - + android:layout_above="@+id/homeworkDialogClose" + android:layout_alignParentTop="true" + tools:itemCount="1" + tools:listitem="@layout/item_homework_dialog_details" /> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/app/src/main/res/layout/item_homework_dialog_attachment.xml b/app/src/main/res/layout/item_homework_dialog_attachment.xml new file mode 100644 index 000000000..ec0b37f2f --- /dev/null +++ b/app/src/main/res/layout/item_homework_dialog_attachment.xml @@ -0,0 +1,21 @@ + + + + diff --git a/app/src/main/res/layout/item_homework_dialog_attachments_header.xml b/app/src/main/res/layout/item_homework_dialog_attachments_header.xml new file mode 100644 index 000000000..383cbeaf7 --- /dev/null +++ b/app/src/main/res/layout/item_homework_dialog_attachments_header.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/layout/item_homework_dialog_details.xml b/app/src/main/res/layout/item_homework_dialog_details.xml new file mode 100644 index 000000000..3ef389d0c --- /dev/null +++ b/app/src/main/res/layout/item_homework_dialog_details.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 299345b864b6ab07c6413981f2ad1a08f7a43264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 9 Apr 2020 23:30:56 +0200 Subject: [PATCH 40/61] Fix crash in message preview (#762) --- .../java/io/github/wulkanowy/data/db/dao/StudentDao.kt | 3 +++ .../wulkanowy/data/repositories/student/StudentLocal.kt | 8 ++++++++ .../data/repositories/student/StudentRepository.kt | 6 ++++++ .../ui/modules/message/preview/MessagePreviewFragment.kt | 4 ++-- .../ui/modules/message/preview/MessagePreviewPresenter.kt | 7 ++++--- .../main/java/io/github/wulkanowy/utils/LoggerUtils.kt | 2 +- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt index 57bf25fb8..901ddc73f 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt @@ -22,6 +22,9 @@ interface StudentDao { @Query("SELECT * FROM Students WHERE is_current = 1") fun loadCurrent(): Maybe + @Query("SELECT * FROM Students WHERE id = :id") + fun loadById(id: Int): Maybe + @Query("SELECT * FROM Students") fun loadAll(): Maybe> diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt index a3576ca22..c7a46e9d6 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentLocal.kt @@ -33,6 +33,14 @@ class StudentLocal @Inject constructor( .filter { it.isNotEmpty() } } + fun getStudentById(id: Int): Maybe { + return studentDb.loadById(id).map { + it.apply { + if (Sdk.Mode.valueOf(loginMode) != Sdk.Mode.API) password = decrypt(password) + } + } + } + fun getCurrentStudent(decryptPass: Boolean): Maybe { return studentDb.loadCurrent().map { it.apply { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt index 270d080e1..bebd1eb9c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/student/StudentRepository.kt @@ -47,6 +47,12 @@ class StudentRepository @Inject constructor( return local.getStudents(decryptPass).toSingle(emptyList()) } + fun getStudentById(id: Int): Single { + return local.getStudentById(id) + .switchIfEmpty(Maybe.error(NoCurrentStudentException())) + .toSingle() + } + fun getCurrentStudent(decryptPass: Boolean = true): Single { return local.getCurrentStudent(decryptPass) .switchIfEmpty(Maybe.error(NoCurrentStudentException())) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt index 3f52be895..953238c08 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewFragment.kt @@ -63,7 +63,7 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) messageContainer = messagePreviewContainer - presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as Message) + presenter.onAttachView(this, (savedInstanceState ?: arguments)?.getSerializable(MESSAGE_ID_KEY) as? Message) } override fun initView() { @@ -150,8 +150,8 @@ class MessagePreviewFragment : BaseFragment(), MessagePreviewView, MainView.Titl } override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) outState.putSerializable(MESSAGE_ID_KEY, presenter.message) + super.onSaveInstanceState(outState) } override fun onDestroyView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 7bf9c05e7..5a19d9fab 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -24,11 +24,12 @@ class MessagePreviewPresenter @Inject constructor( private var retryCallback: () -> Unit = {} - fun onAttachView(view: MessagePreviewView, message: Message) { + fun onAttachView(view: MessagePreviewView, message: Message?) { super.onAttachView(view) view.initView() errorHandler.showErrorMessage = ::showErrorViewOnError - loadData(message) + this.message = message + loadData(requireNotNull(message)) } private fun onMessageLoadRetry(message: Message) { @@ -47,7 +48,7 @@ class MessagePreviewPresenter @Inject constructor( Timber.i("Loading message ${message.messageId} preview started") disposable.apply { clear() - add(studentRepository.getCurrentStudent() + add(studentRepository.getStudentById(message.studentId) .flatMap { messageRepository.getMessage(it, message, true) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) diff --git a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt index 15de40d37..fc3528495 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.kt @@ -18,7 +18,7 @@ class DebugLogTree : Timber.DebugTree() { } } -private fun Bundle?.checkSavedState() = if (this == null) "(STATE IS NULL)" else "" +private fun Bundle?.checkSavedState() = if (this == null) "(STATE IS NULL)" else "(STATE IS NOT NULL)" class ActivityLifecycleLogger : Application.ActivityLifecycleCallbacks { From a0528496eb94a1c6cbe01e9b778ad11f7bb4c729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 9 Apr 2020 23:46:42 +0200 Subject: [PATCH 41/61] Fix crash caused by updating view in not attached fragment (#763) --- .../ui/modules/settings/SettingsFragment.kt | 2 ++ .../ui/modules/settings/SettingsPresenter.kt | 25 ++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt index 5a8593a06..fe0a97632 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsFragment.kt @@ -82,6 +82,8 @@ class SettingsFragment : PreferenceFragmentCompat(), } override fun setSyncInProgress(inProgress: Boolean) { + if (activity == null || !isAdded) return + findPreference(getString(R.string.pref_key_services_force_sync))?.run { isEnabled = !inProgress summary = if (inProgress) getString(R.string.pref_services_sync_in_progress) else "" diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt index ce5100ea8..c8545ac0e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/SettingsPresenter.kt @@ -58,16 +58,29 @@ class SettingsPresenter @Inject constructor( fun onForceSyncDialogSubmit() { view?.run { - Timber.i("Setting sync now started") - analytics.logEvent("sync_now_started") + val successString = syncSuccessString + val failedString = syncFailedString disposable.add(syncManager.startOneTimeSyncWorker() - .doOnSubscribe { setSyncInProgress(true) } + .doOnSubscribe { + setSyncInProgress(true) + Timber.i("Setting sync now started") + analytics.logEvent("sync_now", "status" to "started") + } .doFinally { setSyncInProgress(false) } .subscribe({ workInfo -> - if (workInfo.state == WorkInfo.State.SUCCEEDED) showMessage(syncSuccessString) - else if (workInfo.state == WorkInfo.State.FAILED) showError(syncFailedString, Throwable(workInfo.outputData.getString("error"))) + when (workInfo.state) { + WorkInfo.State.SUCCEEDED -> { + showMessage(successString) + analytics.logEvent("sync_now", "status" to "success") + } + WorkInfo.State.FAILED -> { + showError(failedString, Throwable(workInfo.outputData.getString("error"))) + analytics.logEvent("sync_now", "status" to "failed") + } + else -> Timber.d("Sync now state: ${workInfo.state}") + } }, { - Timber.e("Sync now failed") + Timber.e(it, "Sync now failed") }) ) } From 11c285be0198785c5413f9aa1f83c859a80b0910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 12 Apr 2020 15:12:25 +0200 Subject: [PATCH 42/61] Fix homework dialog size (#765) --- app/src/main/res/layout/dialog_homework.xml | 60 +++++++++++-------- .../layout/item_homework_dialog_details.xml | 2 + 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/app/src/main/res/layout/dialog_homework.xml b/app/src/main/res/layout/dialog_homework.xml index a2c2ec470..daa076363 100644 --- a/app/src/main/res/layout/dialog_homework.xml +++ b/app/src/main/res/layout/dialog_homework.xml @@ -1,39 +1,47 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - + - - + + + + + diff --git a/app/src/main/res/layout/item_homework_dialog_details.xml b/app/src/main/res/layout/item_homework_dialog_details.xml index 3ef389d0c..4b368c626 100644 --- a/app/src/main/res/layout/item_homework_dialog_details.xml +++ b/app/src/main/res/layout/item_homework_dialog_details.xml @@ -88,6 +88,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="3dp" + android:layout_marginBottom="10dp" + android:autoLink="web" android:lineSpacingMultiplier="1.2" android:text="@string/all_no_data" android:textIsSelectable="true" From 76af623c941445dbbfd4c323d71cf5a715c6ae1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 12 Apr 2020 15:13:35 +0200 Subject: [PATCH 43/61] Add Sdk.init(student) call in all remote repositories (#764) --- app/build.gradle | 2 +- .../data/repositories/TestEntityCreator.kt | 29 ++++++ .../repositories/student/StudentLocalTest.kt | 10 +- .../timetable/TimetableRepositoryTest.kt | 7 +- .../io/github/wulkanowy/data/SdkHelper.kt | 30 ------ .../attendance/AttendanceRemote.kt | 11 ++- .../attendance/AttendanceRepository.kt | 41 ++++---- .../AttendanceSummaryRemote.kt | 7 +- .../AttendanceSummaryRepository.kt | 5 +- .../CompletedLessonsRemote.kt | 7 +- .../CompletedLessonsRepository.kt | 38 ++++---- .../data/repositories/exam/ExamRemote.kt | 7 +- .../data/repositories/exam/ExamRepository.kt | 38 ++++---- .../data/repositories/grade/GradeRemote.kt | 7 +- .../repositories/grade/GradeRepository.kt | 2 +- .../gradessummary/GradeSummaryRemote.kt | 7 +- .../gradessummary/GradeSummaryRepository.kt | 5 +- .../gradestatistics/GradeStatisticsRemote.kt | 11 ++- .../GradeStatisticsRepository.kt | 9 +- .../repositories/homework/HomeworkRemote.kt | 7 +- .../homework/HomeworkRepository.kt | 5 +- .../luckynumber/LuckyNumberRemote.kt | 3 +- .../luckynumber/LuckyNumberRepository.kt | 44 ++++----- .../repositories/message/MessageRemote.kt | 15 +-- .../repositories/message/MessageRepository.kt | 96 +++++++++---------- .../mobiledevice/MobileDeviceRemote.kt | 19 ++-- .../mobiledevice/MobileDeviceRepository.kt | 13 +-- .../data/repositories/note/NoteRemote.kt | 7 +- .../data/repositories/note/NoteRepository.kt | 2 +- .../repositories/recipient/RecipientRemote.kt | 10 +- .../recipient/RecipientRepository.kt | 40 ++++---- .../reportingunit/ReportingUnitRemote.kt | 6 +- .../reportingunit/ReportingUnitRepository.kt | 54 +++++------ .../data/repositories/school/SchoolRemote.kt | 7 +- .../repositories/school/SchoolRepository.kt | 5 +- .../repositories/semester/SemesterRemote.kt | 3 +- .../semester/SemesterRepository.kt | 37 +++---- .../data/repositories/subject/SubjectLocal.kt | 2 +- .../repositories/subject/SubjectRemote.kt | 7 +- .../repositories/subject/SubjectRepository.kt | 5 +- .../repositories/teacher/TeacherRemote.kt | 7 +- .../repositories/teacher/TeacherRepository.kt | 5 +- .../repositories/timetable/TimetableRemote.kt | 7 +- .../timetable/TimetableRepository.kt | 5 +- .../sync/works/AttendanceSummaryWork.kt | 2 +- .../services/sync/works/AttendanceWork.kt | 2 +- .../sync/works/CompletedLessonWork.kt | 2 +- .../wulkanowy/services/sync/works/ExamWork.kt | 2 +- .../sync/works/GradeStatisticsWork.kt | 2 +- .../services/sync/works/GradeSummaryWork.kt | 2 +- .../services/sync/works/HomeworkWork.kt | 2 +- .../services/sync/works/TeacherWork.kt | 2 +- .../services/sync/works/TimetableWork.kt | 2 +- .../modules/attendance/AttendancePresenter.kt | 16 +++- .../summary/AttendanceSummaryPresenter.kt | 16 +++- .../ui/modules/exam/ExamPresenter.kt | 7 +- .../ui/modules/grade/GradeAverageProvider.kt | 8 +- .../statistics/GradeStatisticsPresenter.kt | 23 +++-- .../grade/summary/GradeSummaryPresenter.kt | 2 +- .../ui/modules/homework/HomeworkPresenter.kt | 7 +- .../preview/MessagePreviewPresenter.kt | 3 +- .../message/send/SendMessagePresenter.kt | 3 +- .../mobiledevice/MobileDevicePresenter.kt | 16 ++-- .../token/MobileDeviceTokenPresenter.kt | 7 +- .../school/SchoolPresenter.kt | 7 +- .../teacher/TeacherPresenter.kt | 7 +- .../modules/timetable/TimetablePresenter.kt | 7 +- .../completed/CompletedLessonsPresenter.kt | 7 +- .../timetablewidget/TimetableWidgetFactory.kt | 7 +- .../io/github/wulkanowy/utils/SdkExtension.kt | 29 ++++++ .../data/repositories/TestEnityCreator.kt | 47 +++++++++ .../attendance/AttendanceRemoteTest.kt | 13 ++- .../CompletedLessonsRemoteTest.kt | 12 ++- .../data/repositories/exam/ExamRemoteTest.kt | 24 +++-- .../GradeStatisticsRemoteTest.kt | 14 ++- .../luckynumber/LuckyNumberRemoteTest.kt | 16 ++-- .../message/MessageRepositoryTest.kt | 8 +- .../MobileDeviceRepositoryTest.kt | 7 +- .../semester/SemesterRepositoryTest.kt | 21 +--- .../semester/TestSemesterEnityCreator.kt | 19 ---- .../timetable/TimetableRemoteTest.kt | 10 +- .../modules/grade/GradeAverageProviderTest.kt | 20 ++-- 82 files changed, 609 insertions(+), 476 deletions(-) create mode 100644 app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestEntityCreator.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt create mode 100644 app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt create mode 100644 app/src/test/java/io/github/wulkanowy/data/repositories/TestEnityCreator.kt delete mode 100644 app/src/test/java/io/github/wulkanowy/data/repositories/semester/TestSemesterEnityCreator.kt diff --git a/app/build.gradle b/app/build.gradle index 9eeb3e7d9..c05cb8b41 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,7 +128,7 @@ configurations.all { } dependencies { - implementation "io.github.wulkanowy:sdk:0.17.0" + implementation "io.github.wulkanowy:sdk:d842456" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "androidx.core:core-ktx:1.2.0" diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestEntityCreator.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestEntityCreator.kt new file mode 100644 index 000000000..bbbfd83dd --- /dev/null +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/TestEntityCreator.kt @@ -0,0 +1,29 @@ +package io.github.wulkanowy.data.repositories + +import io.github.wulkanowy.data.db.entities.Student +import org.threeten.bp.LocalDateTime + +fun getStudent(): Student { + return Student( + email = "test", + password = "test123", + schoolSymbol = "23", + scrapperBaseUrl = "fakelog.cf", + loginType = "AUTO", + isCurrent = true, + studentName = "", + schoolShortName = "", + schoolName = "", + studentId = 0, + classId = 1, + symbol = "", + registrationDate = LocalDateTime.now(), + className = "", + loginMode = "API", + certificateKey = "", + privateKey = "", + mobileBaseUrl = "", + userLoginId = 0, + isParent = false + ) +} diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt index 5f8be6b15..530bfb3f7 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/student/StudentLocalTest.kt @@ -5,13 +5,11 @@ import androidx.room.Room import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import io.github.wulkanowy.data.db.AppDatabase -import io.github.wulkanowy.data.db.SharedPrefProvider -import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.repositories.getStudent import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.threeten.bp.LocalDateTime.now import kotlin.test.assertEquals @RunWith(AndroidJUnit4::class) @@ -21,14 +19,13 @@ class StudentLocalTest { private lateinit var testDb: AppDatabase - private lateinit var sharedProvider: SharedPrefProvider + private val student = getStudent() @Before fun createDb() { val context = ApplicationProvider.getApplicationContext() testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) .build() - sharedProvider = SharedPrefProvider(context.getSharedPreferences("TEST", Context.MODE_PRIVATE)) studentLocal = StudentLocal(testDb.studentDao, context) } @@ -39,8 +36,7 @@ class StudentLocalTest { @Test fun saveAndReadTest() { - studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", scrapperBaseUrl = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolShortName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "", loginMode = "API", certificateKey = "", privateKey = "", mobileBaseUrl = "", userLoginId = 0, isParent = false))) - .blockingGet() + studentLocal.saveStudents(listOf(student)).blockingGet() val student = studentLocal.getCurrentStudent(true).blockingGet() assertEquals("23", student.schoolSymbol) diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt index 565425d43..fdf193a26 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepositoryTest.kt @@ -9,6 +9,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy +import io.github.wulkanowy.data.repositories.getStudent import io.github.wulkanowy.sdk.Sdk import io.mockk.MockKAnnotations import io.mockk.every @@ -33,6 +34,8 @@ class TimetableRepositoryTest { .strategy(TestInternetObservingStrategy()) .build() + private val student = getStudent() + @MockK private lateinit var semesterMock: Semester @@ -78,7 +81,7 @@ class TimetableRepositoryTest { )) val lessons = TimetableRepository(settings, timetableLocal, timetableRemote) - .getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true) + .getTimetable(student, semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true) .blockingGet() assertEquals(4, lessons.size) @@ -124,7 +127,7 @@ class TimetableRepositoryTest { )) val lessons = TimetableRepository(settings, timetableLocal, timetableRemote) - .getTimetable(semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true) + .getTimetable(student, semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true) .blockingGet() assertEquals(12, lessons.size) diff --git a/app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt b/app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt deleted file mode 100644 index 901712594..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/SdkHelper.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.wulkanowy.data - -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.sdk.Sdk -import javax.inject.Inject - -class SdkHelper @Inject constructor(private val sdk: Sdk) { - - fun init(student: Student) { - sdk.apply { - email = student.email - password = student.password - symbol = student.symbol - schoolSymbol = student.schoolSymbol - studentId = student.studentId - classId = student.classId - - if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) { - scrapperBaseUrl = student.scrapperBaseUrl - loginType = Sdk.ScrapperLoginType.valueOf(student.loginType) - } - loginId = student.userLoginId - - mode = Sdk.Mode.valueOf(student.loginMode) - mobileBaseUrl = student.mobileBaseUrl - certKey = student.certificateKey - privateKey = student.privateKey - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt index 1828c2bdf..f64d920db 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemote.kt @@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.attendance import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Absent +import io.github.wulkanowy.utils.init import io.reactivex.Single import org.threeten.bp.LocalDate import org.threeten.bp.LocalDateTime @@ -14,8 +16,9 @@ import javax.inject.Singleton @Singleton class AttendanceRemote @Inject constructor(private val sdk: Sdk) { - fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendance(startDate, endDate, semester.semesterId) + fun getAttendance(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getAttendance(startDate, endDate, semester.semesterId) .map { attendance -> attendance.map { Attendance( @@ -39,8 +42,8 @@ class AttendanceRemote @Inject constructor(private val sdk: Sdk) { } } - fun excuseAbsence(semester: Semester, absenceList: List, reason: String?): Single { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance -> + fun excuseAbsence(student: Student, semester: Semester, absenceList: List, reason: String?): Single { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance -> Absent( date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)), timeId = attendance.timeId diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt index fc3830c2e..22fe7fa51 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.uniqueSubtract @@ -20,29 +21,25 @@ class AttendanceRepository @Inject constructor( private val remote: AttendanceRemote ) { - fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean) - : Single> { - return Single.fromCallable { startDate.monday to endDate.friday } - .flatMap { dates -> - local.getAttendance(semester, dates.first, dates.second).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap { - if (it) remote.getAttendance(semester, dates.first, dates.second) - else Single.error(UnknownHostException()) - }.flatMap { newAttendance -> - local.getAttendance(semester, dates.first, dates.second) - .toSingle(emptyList()) - .doOnSuccess { oldAttendance -> - local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance)) - local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance)) - } - }.flatMap { - local.getAttendance(semester, dates.first, dates.second) - .toSingle(emptyList()) - }).map { list -> list.filter { it.date in startDate..endDate } } - } + fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean): Single> { + return local.getAttendance(semester, start.monday, end.friday).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap { + if (it) remote.getAttendance(student, semester, start.monday, end.friday) + else Single.error(UnknownHostException()) + }.flatMap { newAttendance -> + local.getAttendance(semester, start.monday, end.friday) + .toSingle(emptyList()) + .doOnSuccess { oldAttendance -> + local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance)) + local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance)) + } + }.flatMap { + local.getAttendance(semester, start.monday, end.friday) + .toSingle(emptyList()) + }).map { list -> list.filter { it.date in start..end } } } - fun excuseForAbsence(semester: Semester, attendanceList: List, reason: String? = null): Single { - return remote.excuseAbsence(semester, attendanceList, reason) + fun excuseForAbsence(student: Student, semester: Semester, attendanceList: List, reason: String? = null): Single { + return remote.excuseAbsence(student, semester, attendanceList, reason) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt index c167427f7..8fef5c391 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.attendancesummary import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -10,8 +12,9 @@ import javax.inject.Singleton @Singleton class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) { - fun getAttendanceSummary(semester: Semester, subjectId: Int): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendanceSummary(subjectId) + fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getAttendanceSummary(subjectId) .map { attendance -> attendance.map { AttendanceSummary( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt index c65870508..5f0b2b346 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/attendancesummary/AttendanceSummaryRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.uniqueSubtract import io.reactivex.Single import java.net.UnknownHostException @@ -17,11 +18,11 @@ class AttendanceSummaryRepository @Inject constructor( private val remote: AttendanceSummaryRemote ) { - fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single> { + fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single> { return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getAttendanceSummary(semester, subjectId) + if (it) remote.getAttendanceSummary(student, semester, subjectId) else Single.error(UnknownHostException()) }.flatMap { new -> local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt index ca680f209..bb115111e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.completedlessons import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import org.threeten.bp.LocalDate import javax.inject.Inject @@ -11,8 +13,9 @@ import javax.inject.Singleton @Singleton class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) { - fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getCompletedLessons(startDate, endDate) + fun getCompletedLessons(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getCompletedLessons(startDate, endDate) .map { lessons -> lessons.map { it.absence diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt index c22fabc39..f31e30552 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.uniqueSubtract @@ -20,25 +21,22 @@ class CompletedLessonsRepository @Inject constructor( private val remote: CompletedLessonsRemote ) { - fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single> { - return Single.fromCallable { startDate.monday to endDate.friday } - .flatMap { dates -> - local.getCompletedLessons(semester, dates.first, dates.second).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getCompletedLessons(semester, dates.first, dates.second) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getCompletedLessons(semester, dates.first, dates.second) - .toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteCompleteLessons(old.uniqueSubtract(new)) - local.saveCompletedLessons(new.uniqueSubtract(old)) - } - }.flatMap { - local.getCompletedLessons(semester, dates.first, dates.second) - .toSingle(emptyList()) - }).map { list -> list.filter { it.date in startDate..endDate } } - } + fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> { + return local.getCompletedLessons(semester, start.monday, end.friday).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getCompletedLessons(student, semester, start.monday, end.friday) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getCompletedLessons(semester, start.monday, end.friday) + .toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteCompleteLessons(old.uniqueSubtract(new)) + local.saveCompletedLessons(new.uniqueSubtract(old)) + } + }.flatMap { + local.getCompletedLessons(semester, start.monday, end.friday) + .toSingle(emptyList()) + }).map { list -> list.filter { it.date in start..end } } } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt index ea7ec9441..fb105ceee 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.exam import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import org.threeten.bp.LocalDate import javax.inject.Inject @@ -11,8 +13,9 @@ import javax.inject.Singleton @Singleton class ExamRemote @Inject constructor(private val sdk: Sdk) { - fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getExams(startDate, endDate, semester.semesterId) + fun getExams(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getExams(startDate, endDate, semester.semesterId) .map { exams -> exams.map { Exam( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt index be60eaecd..452a15510 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/exam/ExamRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.uniqueSubtract @@ -20,25 +21,22 @@ class ExamRepository @Inject constructor( private val remote: ExamRemote ) { - fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single> { - return Single.fromCallable { startDate.monday to endDate.friday } - .flatMap { dates -> - local.getExams(semester, dates.first, dates.second).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getExams(semester, dates.first, dates.second) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getExams(semester, dates.first, dates.second) - .toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteExams(old.uniqueSubtract(new)) - local.saveExams(new.uniqueSubtract(old)) - } - }.flatMap { - local.getExams(semester, dates.first, dates.second) - .toSingle(emptyList()) - }).map { list -> list.filter { it.date in startDate..endDate } } - } + fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> { + return local.getExams(semester, start.monday, end.friday).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getExams(student, semester, start.monday, end.friday) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getExams(semester, start.monday, end.friday) + .toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteExams(old.uniqueSubtract(new)) + local.saveExams(new.uniqueSubtract(old)) + } + }.flatMap { + local.getExams(semester, start.monday, end.friday) + .toSingle(emptyList()) + }).map { list -> list.filter { it.date in start..end } } } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt index d07ac6d1c..6f19095ba 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.grade import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -10,8 +12,9 @@ import javax.inject.Singleton @Singleton class GradeRemote @Inject constructor(private val sdk: Sdk) { - fun getGrades(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGrades(semester.semesterId) + fun getGrades(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getGrades(semester.semesterId) .map { grades -> grades.map { Grade( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt index 7f8e92a2e..351ebc392 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/grade/GradeRepository.kt @@ -23,7 +23,7 @@ class GradeRepository @Inject constructor( return local.getGrades(semester).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getGrades(semester) + if (it) remote.getGrades(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getGrades(semester).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt index 2681fe058..1b09974dd 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.gradessummary import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -10,8 +12,9 @@ import javax.inject.Singleton @Singleton class GradeSummaryRemote @Inject constructor(private val sdk: Sdk) { - fun getGradeSummary(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesSummary(semester.semesterId) + fun getGradeSummary(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getGradesSummary(semester.semesterId) .map { gradesSummary -> gradesSummary.map { GradeSummary( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt index 660a032c2..f1d7a6c1c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradessummary/GradeSummaryRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.uniqueSubtract import io.reactivex.Single import java.net.UnknownHostException @@ -17,11 +18,11 @@ class GradeSummaryRepository @Inject constructor( private val remote: GradeSummaryRemote ) { - fun getGradesSummary(semester: Semester, forceRefresh: Boolean = false): Single> { + fun getGradesSummary(student: Student, semester: Semester, forceRefresh: Boolean = false): Single> { return local.getGradesSummary(semester).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getGradeSummary(semester) + if (it) remote.getGradeSummary(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getGradesSummary(semester).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt index f10f30369..99e0cb987 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemote.kt @@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.gradestatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -11,8 +13,8 @@ import javax.inject.Singleton @Singleton class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) { - fun getGradeStatistics(semester: Semester, isSemester: Boolean): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).let { + fun getGradeStatistics(student: Student, semester: Semester, isSemester: Boolean): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).let { if (isSemester) it.getGradesAnnualStatistics(semester.semesterId) else it.getGradesPartialStatistics(semester.semesterId) }.map { gradeStatistics -> @@ -29,8 +31,9 @@ class GradeStatisticsRemote @Inject constructor(private val sdk: Sdk) { } } - fun getGradePointsStatistics(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getGradesPointsStatistics(semester.semesterId) + fun getGradePointsStatistics(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getGradesPointsStatistics(semester.semesterId) .map { gradePointsStatistics -> gradePointsStatistics.map { GradePointsStatistics( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt index e82e9db4d..8d96d2f57 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRepository.kt @@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradeStatistics import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.pojos.GradeStatisticsItem import io.github.wulkanowy.ui.modules.grade.statistics.ViewType import io.github.wulkanowy.utils.uniqueSubtract @@ -20,11 +21,11 @@ class GradeStatisticsRepository @Inject constructor( private val remote: GradeStatisticsRemote ) { - fun getGradesStatistics(semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single> { + fun getGradesStatistics(student: Student, semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single> { return local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getGradeStatistics(semester, isSemester) + if (it) remote.getGradeStatistics(student, semester, isSemester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getGradesStatistics(semester, isSemester).toSingle(emptyList()) @@ -35,11 +36,11 @@ class GradeStatisticsRepository @Inject constructor( }.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.toSingle(emptyList()) }) } - fun getGradesPointsStatistics(semester: Semester, subjectName: String, forceRefresh: Boolean): Single> { + fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean): Single> { return local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getGradePointsStatistics(semester) + if (it) remote.getGradePointsStatistics(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getGradesPointsStatistics(semester).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt index bbaea1e34..20ffee99c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.homework import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import org.threeten.bp.LocalDate import javax.inject.Inject @@ -11,8 +13,9 @@ import javax.inject.Singleton @Singleton class HomeworkRemote @Inject constructor(private val sdk: Sdk) { - fun getHomework(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getHomework(startDate, endDate) + fun getHomework(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getHomework(startDate, endDate) .map { homework -> homework.map { Homework( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt index e506bdb94..4454fd88e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/homework/HomeworkRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.uniqueSubtract @@ -21,12 +22,12 @@ class HomeworkRepository @Inject constructor( private val remote: HomeworkRemote ) { - fun getHomework(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> { + fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> { return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) -> local.getHomework(semester, monday, friday).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getHomework(semester, monday, friday) + if (it) remote.getHomework(student, semester, monday, friday) else Single.error(UnknownHostException()) }.flatMap { new -> local.getHomework(semester, monday, friday).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt index 2fcf9338b..0c71897a6 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemote.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.luckynumber import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Maybe import org.threeten.bp.LocalDate import javax.inject.Inject @@ -12,7 +13,7 @@ import javax.inject.Singleton class LuckyNumberRemote @Inject constructor(private val sdk: Sdk) { fun getLuckyNumber(student: Student): Maybe { - return sdk.getLuckyNumber(student.schoolShortName).map { + return sdk.init(student).getLuckyNumber(student.schoolShortName).map { LuckyNumber( studentId = student.studentId, date = LocalDate.now(), diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt index 0ea063501..374b9a294 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRepository.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.luckynumber import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.Student import io.reactivex.Completable @@ -16,36 +15,33 @@ import javax.inject.Singleton class LuckyNumberRepository @Inject constructor( private val settings: InternetObservingSettings, private val local: LuckyNumberLocal, - private val remote: LuckyNumberRemote, - private val sdkHelper: SdkHelper + private val remote: LuckyNumberRemote ) { fun getLuckyNumber(student: Student, forceRefresh: Boolean = false, notify: Boolean = false): Maybe { - return Maybe.just(sdkHelper.init(student)).flatMap { - local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMapMaybe { - if (it) remote.getLuckyNumber(student) - else Maybe.error(UnknownHostException()) - }.flatMap { new -> - local.getLuckyNumber(student, LocalDate.now()) - .doOnSuccess { old -> - if (new != old) { - local.deleteLuckyNumber(old) - local.saveLuckyNumber(new.apply { - if (notify) isNotified = false - }) - } - } - .doOnComplete { + return local.getLuckyNumber(student, LocalDate.now()).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMapMaybe { + if (it) remote.getLuckyNumber(student) + else Maybe.error(UnknownHostException()) + }.flatMap { new -> + local.getLuckyNumber(student, LocalDate.now()) + .doOnSuccess { old -> + if (new != old) { + local.deleteLuckyNumber(old) local.saveLuckyNumber(new.apply { if (notify) isNotified = false }) } - }.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) }, - { local.getLuckyNumber(student, LocalDate.now()) }) - ) - } + } + .doOnComplete { + local.saveLuckyNumber(new.apply { + if (notify) isNotified = false + }) + } + }.flatMap({ local.getLuckyNumber(student, LocalDate.now()) }, { Maybe.error(it) }, + { local.getLuckyNumber(student, LocalDate.now()) }) + ) } fun getNotNotifiedLuckyNumber(student: Student): Maybe { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt index 488522109..1808c048b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRemote.kt @@ -8,6 +8,7 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.sdk.pojo.SentMessage +import io.github.wulkanowy.utils.init import io.reactivex.Single import org.threeten.bp.LocalDateTime.now import javax.inject.Inject @@ -18,7 +19,7 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient class MessageRemote @Inject constructor(private val sdk: Sdk) { fun getMessages(student: Student, semester: Semester, folder: MessageFolder): Single> { - return sdk.getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages -> + return sdk.init(student).getMessages(Folder.valueOf(folder.name), semester.start.atStartOfDay(), semester.end.atStartOfDay()).map { messages -> messages.map { Message( studentId = student.id.toInt(), @@ -41,8 +42,8 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) { } } - fun getMessagesContentDetails(message: Message, markAsRead: Boolean = false): Single>> { - return sdk.getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details -> + fun getMessagesContentDetails(student: Student, message: Message, markAsRead: Boolean = false): Single>> { + return sdk.init(student).getMessageDetails(message.messageId, message.folderId, markAsRead, message.realId).map { details -> details.content to details.attachments.map { MessageAttachment( realId = it.id, @@ -55,8 +56,8 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) { } } - fun sendMessage(subject: String, content: String, recipients: List): Single { - return sdk.sendMessage( + fun sendMessage(student: Student, subject: String, content: String, recipients: List): Single { + return sdk.init(student).sendMessage( subject = subject, content = content, recipients = recipients.map { @@ -73,7 +74,7 @@ class MessageRemote @Inject constructor(private val sdk: Sdk) { ) } - fun deleteMessage(message: Message): Single { - return sdk.deleteMessages(listOf(Pair(message.realId, message.folderId))) + fun deleteMessage(student: Student, message: Message): Single { + return sdk.init(student).deleteMessages(listOf(Pair(message.realId, message.folderId))) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt index 396d5f689..2d2c0430c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/message/MessageRepository.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.message import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.Recipient @@ -22,60 +21,53 @@ import javax.inject.Singleton class MessageRepository @Inject constructor( private val settings: InternetObservingSettings, private val local: MessageLocal, - private val remote: MessageRemote, - private val sdkHelper: SdkHelper + private val remote: MessageRemote ) { fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single> { - return Single.just(sdkHelper.init(student)) - .flatMap { _ -> - local.getMessages(student, folder).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getMessages(student, semester, folder) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getMessages(student, folder).toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteMessages(old.uniqueSubtract(new)) - local.saveMessages(new.uniqueSubtract(old) - .onEach { - it.isNotified = !notify - }) - } - }.flatMap { local.getMessages(student, folder).toSingle(emptyList()) } - ) - } + return local.getMessages(student, folder).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getMessages(student, semester, folder) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getMessages(student, folder).toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteMessages(old.uniqueSubtract(new)) + local.saveMessages(new.uniqueSubtract(old) + .onEach { + it.isNotified = !notify + }) + } + }.flatMap { local.getMessages(student, folder).toSingle(emptyList()) } + ) } fun getMessage(student: Student, message: Message, markAsRead: Boolean = false): Single { - return Single.just(sdkHelper.init(student)) - .flatMap { _ -> - local.getMessageWithAttachment(student, message) - .filter { - it.message.content.isNotEmpty().also { status -> - Timber.d("Message content in db empty: ${!status}") - } && !it.message.unread - } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) local.getMessageWithAttachment(student, message) - else Single.error(UnknownHostException()) - } - .flatMap { dbMessage -> - remote.getMessagesContentDetails(dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) -> - local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply { - id = dbMessage.message.id - content = content.ifBlank { downloadedMessage } - })) - local.saveMessageAttachments(attachments) - Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read") - } - }.flatMap { - local.getMessageWithAttachment(student, message) - } - ) + return local.getMessageWithAttachment(student, message) + .filter { + it.message.content.isNotEmpty().also { status -> + Timber.d("Message content in db empty: ${!status}") + } && !it.message.unread } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) local.getMessageWithAttachment(student, message) + else Single.error(UnknownHostException()) + } + .flatMap { dbMessage -> + remote.getMessagesContentDetails(student, dbMessage.message, markAsRead).doOnSuccess { (downloadedMessage, attachments) -> + local.updateMessages(listOf(dbMessage.message.copy(unread = !markAsRead).apply { + id = dbMessage.message.id + content = content.ifBlank { downloadedMessage } + })) + local.saveMessageAttachments(attachments) + Timber.d("Message ${message.messageId} with blank content: ${dbMessage.message.content.isBlank()}, marked as read") + } + }.flatMap { + local.getMessageWithAttachment(student, message) + } + ) } fun getNotNotifiedMessages(student: Student): Single> { @@ -88,18 +80,18 @@ class MessageRepository @Inject constructor( return Completable.fromCallable { local.updateMessages(messages) } } - fun sendMessage(subject: String, content: String, recipients: List): Single { + fun sendMessage(student: Student, subject: String, content: String, recipients: List): Single { return ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.sendMessage(subject, content, recipients) + if (it) remote.sendMessage(student, subject, content, recipients) else Single.error(UnknownHostException()) } } - fun deleteMessage(message: Message): Single { + fun deleteMessage(student: Student, message: Message): Single { return ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.deleteMessage(message) + if (it) remote.deleteMessage(student, message) else Single.error(UnknownHostException()) } .doOnSuccess { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt index c43c3f21e..800f95971 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRemote.kt @@ -2,8 +2,10 @@ package io.github.wulkanowy.data.repositories.mobiledevice import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -11,13 +13,14 @@ import javax.inject.Singleton @Singleton class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) { - fun getDevices(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getRegisteredDevices() + fun getDevices(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getRegisteredDevices() .map { devices -> devices.map { MobileDevice( studentId = semester.studentId, - date = it.date, + date = it.createDate, deviceId = it.id, name = it.name ) @@ -25,12 +28,14 @@ class MobileDeviceRemote @Inject constructor(private val sdk: Sdk) { } } - fun unregisterDevice(semester: Semester, device: MobileDevice): Single { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).unregisterDevice(device.deviceId) + fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice): Single { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .unregisterDevice(device.deviceId) } - fun getToken(semester: Semester): Single { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getToken() + fun getToken(student: Student, semester: Semester): Single { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getToken() .map { MobileDeviceToken( token = it.token, diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt index ac450ff46..545846e85 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.utils.uniqueSubtract import io.reactivex.Single @@ -18,11 +19,11 @@ class MobileDeviceRepository @Inject constructor( private val remote: MobileDeviceRemote ) { - fun getDevices(semester: Semester, forceRefresh: Boolean = false): Single> { + fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean = false): Single> { return local.getDevices(semester).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getDevices(semester) + if (it) remote.getDevices(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getDevices(semester).toSingle(emptyList()) @@ -34,18 +35,18 @@ class MobileDeviceRepository @Inject constructor( ).flatMap { local.getDevices(semester).toSingle(emptyList()) } } - fun unregisterDevice(semester: Semester, device: MobileDevice): Single { + fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice): Single { return ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.unregisterDevice(semester, device) + if (it) remote.unregisterDevice(student, semester, device) else Single.error(UnknownHostException()) } } - fun getToken(semester: Semester): Single { + fun getToken(student: Student, semester: Semester): Single { return ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getToken(semester) + if (it) remote.getToken(student, semester) else Single.error(UnknownHostException()) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt index cd78abd3c..2c62b608d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRemote.kt @@ -2,7 +2,9 @@ package io.github.wulkanowy.data.repositories.note import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -10,8 +12,9 @@ import javax.inject.Singleton @Singleton class NoteRemote @Inject constructor(private val sdk: Sdk) { - fun getNotes(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getNotes(semester.semesterId) + fun getNotes(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getNotes(semester.semesterId) .map { notes -> notes.map { Note( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt index 52cb2d0f5..e155e2bad 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/note/NoteRepository.kt @@ -23,7 +23,7 @@ class NoteRepository @Inject constructor( return local.getNotes(student).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getNotes(semester) + if (it) remote.getNotes(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getNotes(student).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt index f070ea765..e5b16a156 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRemote.kt @@ -3,7 +3,9 @@ package io.github.wulkanowy.data.repositories.recipient import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.ReportingUnit +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -12,15 +14,15 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient @Singleton class RecipientRemote @Inject constructor(private val sdk: Sdk) { - fun getRecipients(role: Int, unit: ReportingUnit): Single> { - return sdk.getRecipients(unit.realId, role) + fun getRecipients(student: Student, role: Int, unit: ReportingUnit): Single> { + return sdk.init(student).getRecipients(unit.realId, role) .map { recipients -> recipients.map { it.toRecipient() } } } - fun getMessageRecipients(message: Message): Single> { - return sdk.getMessageRecipients(message.messageId, message.senderId) + fun getMessageRecipients(student: Student, message: Message): Single> { + return sdk.init(student).getMessageRecipients(message.messageId, message.senderId) .map { recipients -> recipients.map { it.toRecipient() } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt index d29369b94..6f8a72af2 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/recipient/RecipientRepository.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.recipient import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.ReportingUnit @@ -17,36 +16,31 @@ import javax.inject.Singleton class RecipientRepository @Inject constructor( private val settings: InternetObservingSettings, private val local: RecipientLocal, - private val remote: RecipientRemote, - private val sdkHelper: SdkHelper + private val remote: RecipientRemote ) { fun getRecipients(student: Student, role: Int, unit: ReportingUnit, forceRefresh: Boolean = false): Single> { - return Single.just(sdkHelper.init(student)) - .flatMap { _ -> - local.getRecipients(student, role, unit).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getRecipients(role, unit) - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getRecipients(student, role, unit).toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteRecipients(old.uniqueSubtract(new)) - local.saveRecipients(new.uniqueSubtract(old)) - } - }.flatMap { - local.getRecipients(student, role, unit).toSingle(emptyList()) + return local.getRecipients(student, role, unit).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getRecipients(student, role, unit) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getRecipients(student, role, unit).toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteRecipients(old.uniqueSubtract(new)) + local.saveRecipients(new.uniqueSubtract(old)) } - ) - } + }.flatMap { + local.getRecipients(student, role, unit).toSingle(emptyList()) + } + ) } fun getMessageRecipients(student: Student, message: Message): Single> { - return Single.just(sdkHelper.init(student)) - .flatMap { ReactiveNetwork.checkInternetConnectivity(settings) } + return ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getMessageRecipients(message) + if (it) remote.getMessageRecipients(student, message) else Single.error(UnknownHostException()) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt index 5dbabc545..1fd8b08e3 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRemote.kt @@ -1,7 +1,9 @@ package io.github.wulkanowy.data.repositories.reportingunit import io.github.wulkanowy.data.db.entities.ReportingUnit +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -9,8 +11,8 @@ import javax.inject.Singleton @Singleton class ReportingUnitRemote @Inject constructor(private val sdk: Sdk) { - fun getReportingUnits(): Single> { - return sdk.getReportingUnits().map { + fun getReportingUnits(student: Student): Single> { + return sdk.init(student).getReportingUnits().map { it.map { unit -> ReportingUnit( studentId = sdk.studentId, diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt index 4c8370e68..ee5440984 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/reportingunit/ReportingUnitRepository.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.reportingunit import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.ReportingUnit import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.uniqueSubtract @@ -16,41 +15,34 @@ import javax.inject.Singleton class ReportingUnitRepository @Inject constructor( private val settings: InternetObservingSettings, private val local: ReportingUnitLocal, - private val remote: ReportingUnitRemote, - private val sdkHelper: SdkHelper + private val remote: ReportingUnitRemote ) { fun getReportingUnits(student: Student, forceRefresh: Boolean = false): Single> { - return Single.just(sdkHelper.init(student)) - .flatMap { _ -> - local.getReportingUnits(student).filter { !forceRefresh } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getReportingUnits() - else Single.error(UnknownHostException()) - }.flatMap { new -> - local.getReportingUnits(student).toSingle(emptyList()) - .doOnSuccess { old -> - local.deleteReportingUnits(old.uniqueSubtract(new)) - local.saveReportingUnits(new.uniqueSubtract(old)) - } - }.flatMap { local.getReportingUnits(student).toSingle(emptyList()) } - ) - } + return local.getReportingUnits(student).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getReportingUnits(student) + else Single.error(UnknownHostException()) + }.flatMap { new -> + local.getReportingUnits(student).toSingle(emptyList()) + .doOnSuccess { old -> + local.deleteReportingUnits(old.uniqueSubtract(new)) + local.saveReportingUnits(new.uniqueSubtract(old)) + } + }.flatMap { local.getReportingUnits(student).toSingle(emptyList()) } + ) } fun getReportingUnit(student: Student, unitId: Int): Maybe { - return Maybe.just(sdkHelper.init(student)) - .flatMap { _ -> - local.getReportingUnit(student, unitId) - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) getReportingUnits(student, true) - else Single.error(UnknownHostException()) - }.flatMapMaybe { - local.getReportingUnit(student, unitId) - } - ) - } + return local.getReportingUnit(student, unitId) + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) getReportingUnits(student, true) + else Single.error(UnknownHostException()) + }.flatMapMaybe { + local.getReportingUnit(student, unitId) + } + ) } } diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt index 4d5c92a9e..6a95a446b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRemote.kt @@ -2,14 +2,17 @@ package io.github.wulkanowy.data.repositories.school import io.github.wulkanowy.data.db.entities.School import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject class SchoolRemote @Inject constructor(private val sdk: Sdk) { - fun getSchoolInfo(semester: Semester): Single { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSchool() + fun getSchoolInfo(student: Student, semester: Semester): Single { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getSchool() .map { School( studentId = semester.studentId, diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRepository.kt index a352324d2..1715a28d5 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/school/SchoolRepository.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.School import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.reactivex.Maybe import io.reactivex.Single import java.net.UnknownHostException @@ -17,11 +18,11 @@ class SchoolRepository @Inject constructor( private val remote: SchoolRemote ) { - fun getSchoolInfo(semester: Semester, forceRefresh: Boolean = false): Maybe { + fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean = false): Maybe { return local.getSchool(semester).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getSchoolInfo(semester) + if (it) remote.getSchoolInfo(student, semester) else Single.error(UnknownHostException()) }.flatMapMaybe { new -> local.getSchool(semester) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt index f7b98a4b7..90f0e1d71 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRemote.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.semester import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -11,7 +12,7 @@ import javax.inject.Singleton class SemesterRemote @Inject constructor(private val sdk: Sdk) { fun getSemesters(student: Student): Single> { - return sdk.getSemesters().map { semesters -> + return sdk.init(student).getSemesters().map { semesters -> semesters.map { Semester( studentId = student.studentId, diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt index a13658209..dd702b3e0 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/semester/SemesterRepository.kt @@ -2,13 +2,11 @@ package io.github.wulkanowy.data.repositories.semester import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.getCurrentOrLast import io.github.wulkanowy.utils.isCurrent import io.github.wulkanowy.utils.uniqueSubtract -import io.reactivex.Maybe import io.reactivex.Single import java.net.UnknownHostException import javax.inject.Inject @@ -18,31 +16,26 @@ import javax.inject.Singleton class SemesterRepository @Inject constructor( private val remote: SemesterRemote, private val local: SemesterLocal, - private val settings: InternetObservingSettings, - private val sdkHelper: SdkHelper + private val settings: InternetObservingSettings ) { fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false): Single> { - return Maybe.just(sdkHelper.init(student)) + return local.getSemesters(student).filter { !forceRefresh }.filter { + if (refreshOnNoCurrent) { + it.any { semester -> semester.isCurrent } + } else true + }.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - local.getSemesters(student).filter { !forceRefresh }.filter { - if (refreshOnNoCurrent) { - it.any { semester -> semester.isCurrent } - } else true - } - } - .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) - .flatMap { - if (it) remote.getSemesters(student) - else Single.error(UnknownHostException()) - }.flatMap { new -> - if (new.isEmpty()) throw IllegalArgumentException("Empty semester list!") + if (it) remote.getSemesters(student) + else Single.error(UnknownHostException()) + }.flatMap { new -> + if (new.isEmpty()) throw IllegalArgumentException("Empty semester list!") - local.getSemesters(student).toSingle(emptyList()).doOnSuccess { old -> - local.deleteSemesters(old.uniqueSubtract(new)) - local.saveSemesters(new.uniqueSubtract(old)) - } - }.flatMap { local.getSemesters(student).toSingle(emptyList()) }) + local.getSemesters(student).toSingle(emptyList()).doOnSuccess { old -> + local.deleteSemesters(old.uniqueSubtract(new)) + local.saveSemesters(new.uniqueSubtract(old)) + } + }.flatMap { local.getSemesters(student).toSingle(emptyList()) }) } fun getCurrentSemester(student: Student, forceRefresh: Boolean = false): Single { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt index 63e334019..f8c13e6c2 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectLocal.kt @@ -12,7 +12,7 @@ class SubjectLocal @Inject constructor(private val subjectDao: SubjectDao) { fun getSubjects(semester: Semester): Maybe> { return subjectDao.loadAll(semester.diaryId, semester.studentId) - .filter { !it.isEmpty() } + .filter { it.isNotEmpty() } } fun saveSubjects(subjects: List) { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt index 32dbb2f2e..d30232f82 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRemote.kt @@ -1,8 +1,10 @@ package io.github.wulkanowy.data.repositories.subject import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -10,8 +12,9 @@ import javax.inject.Singleton @Singleton class SubjectRemote @Inject constructor(private val sdk: Sdk) { - fun getSubjects(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getSubjects() + fun getSubjects(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getSubjects() .map { subjects -> subjects.map { Subject( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt index 0c5f386b6..649904da1 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/subject/SubjectRepository.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.subject import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.utils.uniqueSubtract import io.reactivex.Single @@ -17,11 +18,11 @@ class SubjectRepository @Inject constructor( private val remote: SubjectRemote ) { - fun getSubjects(semester: Semester, forceRefresh: Boolean = false): Single> { + fun getSubjects(student: Student, semester: Semester, forceRefresh: Boolean = false): Single> { return local.getSubjects(semester).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getSubjects(semester) + if (it) remote.getSubjects(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getSubjects(semester) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt index d4401bfb2..01552f748 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRemote.kt @@ -1,8 +1,10 @@ package io.github.wulkanowy.data.repositories.teacher import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -10,8 +12,9 @@ import javax.inject.Singleton @Singleton class TeacherRemote @Inject constructor(private val sdk: Sdk) { - fun getTeachers(semester: Semester): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTeachers(semester.semesterId) + fun getTeachers(student: Student, semester: Semester): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getTeachers(semester.semesterId) .map { teachers -> teachers.map { Teacher( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRepository.kt index 19e7a32b8..3c10be73f 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/teacher/TeacherRepository.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.teacher import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.utils.uniqueSubtract import io.reactivex.Single @@ -17,11 +18,11 @@ class TeacherRepository @Inject constructor( private val remote: TeacherRemote ) { - fun getTeachers(semester: Semester, forceRefresh: Boolean = false): Single> { + fun getTeachers(student: Student, semester: Semester, forceRefresh: Boolean = false): Single> { return local.getTeachers(semester).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { - if (it) remote.getTeachers(semester) + if (it) remote.getTeachers(student, semester) else Single.error(UnknownHostException()) }.flatMap { new -> local.getTeachers(semester).toSingle(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt index c0aa16ebb..22cb947db 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemote.kt @@ -1,8 +1,10 @@ package io.github.wulkanowy.data.repositories.timetable import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.reactivex.Single import org.threeten.bp.LocalDate import javax.inject.Inject @@ -11,8 +13,9 @@ import javax.inject.Singleton @Singleton class TimetableRemote @Inject constructor(private val sdk: Sdk) { - fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { - return sdk.switchDiary(semester.diaryId, semester.schoolYear).getTimetable(startDate, endDate) + fun getTimetable(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): Single> { + return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) + .getTimetable(startDate, endDate) .map { lessons -> lessons.map { Timetable( diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt index 20e183c25..42812b30f 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/timetable/TimetableRepository.kt @@ -3,6 +3,7 @@ package io.github.wulkanowy.data.repositories.timetable import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.monday @@ -20,11 +21,11 @@ class TimetableRepository @Inject constructor( private val remote: TimetableRemote ) { - fun getTimetable(semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> { + fun getTimetable(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean = false): Single> { return Single.fromCallable { start.monday to end.friday }.flatMap { (monday, friday) -> local.getTimetable(semester, monday, friday).filter { !forceRefresh } .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap { - if (it) remote.getTimetable(semester, monday, friday) + if (it) remote.getTimetable(student, semester, monday, friday) else Single.error(UnknownHostException()) }.flatMap { new -> local.getTimetable(semester, monday, friday) diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt index 01978c5b6..5f7d7efa2 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceSummaryWork.kt @@ -11,7 +11,7 @@ class AttendanceSummaryWork @Inject constructor( ) : Work { override fun create(student: Student, semester: Semester): Completable { - return attendanceSummaryRepository.getAttendanceSummary(semester, -1, true).ignoreElement() + return attendanceSummaryRepository.getAttendanceSummary(student, semester, -1, true).ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt index e4b55b0ea..e8579ddba 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/AttendanceWork.kt @@ -12,7 +12,7 @@ import javax.inject.Inject class AttendanceWork @Inject constructor(private val attendanceRepository: AttendanceRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return attendanceRepository.getAttendance(semester, now().monday, now().friday, true) + return attendanceRepository.getAttendance(student, semester, now().monday, now().friday, true) .ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt index 29642ad6f..0da597e0a 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/CompletedLessonWork.kt @@ -14,7 +14,7 @@ class CompletedLessonWork @Inject constructor( ) : Work { override fun create(student: Student, semester: Semester): Completable { - return completedLessonsRepository.getCompletedLessons(semester, now().monday, now().friday, true) + return completedLessonsRepository.getCompletedLessons(student, semester, now().monday, now().friday, true) .ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt index 8744fcc79..c6110bbbf 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/ExamWork.kt @@ -12,6 +12,6 @@ import javax.inject.Inject class ExamWork @Inject constructor(private val examRepository: ExamRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return examRepository.getExams(semester, now().monday, now().friday, true).ignoreElement() + return examRepository.getExams(student, semester, now().monday, now().friday, true).ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt index 1de39a95f..327c71740 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeStatisticsWork.kt @@ -9,7 +9,7 @@ import javax.inject.Inject class GradeStatisticsWork @Inject constructor(private val gradeStatisticsRepository: GradeStatisticsRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return gradeStatisticsRepository.getGradesStatistics(semester, "Wszystkie", false, true) + return gradeStatisticsRepository.getGradesStatistics(student, semester, "Wszystkie", false, true) .ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt index 6de0bc5b0..4c8e955d1 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/GradeSummaryWork.kt @@ -9,6 +9,6 @@ import javax.inject.Inject class GradeSummaryWork @Inject constructor(private val gradeSummaryRepository: GradeSummaryRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return gradeSummaryRepository.getGradesSummary(semester, true).ignoreElement() + return gradeSummaryRepository.getGradesSummary(student, semester, true).ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt index 32b356c68..cf3484394 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/HomeworkWork.kt @@ -12,6 +12,6 @@ import javax.inject.Inject class HomeworkWork @Inject constructor(private val homeworkRepository: HomeworkRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return homeworkRepository.getHomework(semester, now().monday, now().friday, true).ignoreElement() + return homeworkRepository.getHomework(student, semester, now().monday, now().friday, true).ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt index 18178d2d1..5a7a41d8d 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/TeacherWork.kt @@ -9,6 +9,6 @@ import javax.inject.Inject class TeacherWork @Inject constructor(private val teacherRepository: TeacherRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return teacherRepository.getTeachers(semester, true).ignoreElement() + return teacherRepository.getTeachers(student, semester, true).ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt b/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt index 743ae0e83..0990ed67a 100644 --- a/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt +++ b/app/src/main/java/io/github/wulkanowy/services/sync/works/TimetableWork.kt @@ -12,7 +12,7 @@ import javax.inject.Inject class TimetableWork @Inject constructor(private val timetableRepository: TimetableRepository) : Work { override fun create(student: Student, semester: Semester): Completable { - return timetableRepository.getTimetable(semester, now().monday, now().friday, true) + return timetableRepository.getTimetable(student, semester, now().monday, now().friday, true) .ignoreElement() } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt index 679d5367d..7fc044744 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/AttendancePresenter.kt @@ -188,13 +188,16 @@ class AttendancePresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() - .delay(200, MILLISECONDS) - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { attendanceRepository.getAttendance(it, date, date, forceRefresh) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + attendanceRepository.getAttendance(student, semester, date, date, forceRefresh) + } + } .map { list -> if (prefRepository.isShowPresent) list else list.filter { !it.presence } } + .delay(200, MILLISECONDS) .map { items -> items.map { AttendanceItem(it) } } .map { items -> items.sortedBy { it.attendance.number } } .subscribeOn(schedulers.backgroundThread) @@ -228,9 +231,12 @@ class AttendancePresenter @Inject constructor( Timber.i("Excusing absence started") disposable.apply { add(studentRepository.getCurrentStudent() + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + attendanceRepository.excuseForAbsence(student, semester, toExcuseList, reason) + } + } .delay(200, MILLISECONDS) - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { attendanceRepository.excuseForAbsence(it, toExcuseList, reason) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doOnSubscribe { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt index 18f67726a..8fc5b6e4a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/attendance/summary/AttendanceSummaryPresenter.kt @@ -83,10 +83,13 @@ class AttendanceSummaryPresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() - .delay(200, MILLISECONDS) - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { attendanceSummaryRepository.getAttendanceSummary(it, subjectId, forceRefresh) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { + attendanceSummaryRepository.getAttendanceSummary(student, it, subjectId, forceRefresh) + } + } .map { createAttendanceSummaryItems(it) to AttendanceSummaryScrollableHeader(formatPercentage(it.calculatePercentage())) } + .delay(200, MILLISECONDS) .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { @@ -126,8 +129,11 @@ class AttendanceSummaryPresenter @Inject constructor( private fun loadSubjects() { Timber.i("Loading attendance summary subjects started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { subjectRepository.getSubjects(it) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + subjectRepository.getSubjects(student, semester) + } + } .doOnSuccess { subjects = it } .map { ArrayList(it.map { subject -> subject.name }) } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt index 35cf5b945..aac9bc4bb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/exam/ExamPresenter.kt @@ -112,9 +112,12 @@ class ExamPresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + examRepository.getExams(student, semester, currentDate.monday, currentDate.friday, forceRefresh) + } + } .delay(200, MILLISECONDS) - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { examRepository.getExams(it, currentDate.monday, currentDate.friday, forceRefresh) } .map { it.groupBy { exam -> exam.date }.toSortedMap() } .map { createExamItems(it) } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt index 37bba4d43..3bb084d3a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -34,7 +34,7 @@ class GradeAverageProvider @Inject constructor( val selectedSemester = semesters.single { it.semesterId == semesterId } val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } - return getAverageFromGradeSummary(selectedSemester, forceRefresh) + return getAverageFromGradeSummary(student, selectedSemester, forceRefresh) .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) .flatMap { firstGrades -> if (selectedSemester == firstSemester) Single.just(firstGrades) @@ -52,7 +52,7 @@ class GradeAverageProvider @Inject constructor( private fun getOnlyOneSemesterAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single>> { val selectedSemester = semesters.single { it.semesterId == semesterId } - return getAverageFromGradeSummary(selectedSemester, forceRefresh) + return getAverageFromGradeSummary(student, selectedSemester, forceRefresh) .switchIfEmpty(gradeRepository.getGrades(student, selectedSemester, forceRefresh) .map { grades -> grades.map { if (student.loginMode == Sdk.Mode.SCRAPPER.name) it.changeModifier(plusModifier, minusModifier) else it } @@ -61,8 +61,8 @@ class GradeAverageProvider @Inject constructor( }) } - private fun getAverageFromGradeSummary(selectedSemester: Semester, forceRefresh: Boolean): Maybe>> { - return gradeSummaryRepository.getGradesSummary(selectedSemester, forceRefresh) + private fun getAverageFromGradeSummary(student: Student, selectedSemester: Semester, forceRefresh: Boolean): Maybe>> { + return gradeSummaryRepository.getGradesSummary(student, selectedSemester, forceRefresh) .toMaybe() .flatMap { if (it.any { summary -> summary.average != .0 }) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt index 4ec0fafe0..6323dbe1e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/statistics/GradeStatisticsPresenter.kt @@ -48,7 +48,6 @@ class GradeStatisticsPresenter @Inject constructor( loadDataByType(semesterId, currentSubjectName, currentType, forceRefresh) } - fun onParentViewReselected() { view?.run { if (!isViewEmpty) resetView() @@ -118,8 +117,11 @@ class GradeStatisticsPresenter @Inject constructor( private fun loadSubjects() { Timber.i("Loading grade stats subjects started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { subjectRepository.getSubjects(it) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + subjectRepository.getSubjects(student, semester) + } + } .doOnSuccess { subjects = it } .map { ArrayList(it.map { subject -> subject.name }) } .subscribeOn(schedulers.backgroundThread) @@ -146,14 +148,15 @@ class GradeStatisticsPresenter @Inject constructor( private fun loadData(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean) { Timber.i("Loading grade stats data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getSemesters(it) } - .flatMap { - val semester = it.first { item -> item.semesterId == semesterId } + .flatMap { student -> + semesterRepository.getSemesters(student).flatMap { semesters -> + val semester = semesters.first { item -> item.semesterId == semesterId } - when (type) { - ViewType.SEMESTER -> gradeStatisticsRepository.getGradesStatistics(semester, subjectName, true, forceRefresh) - ViewType.PARTIAL -> gradeStatisticsRepository.getGradesStatistics(semester, subjectName, false, forceRefresh) - ViewType.POINTS -> gradeStatisticsRepository.getGradesPointsStatistics(semester, subjectName, forceRefresh) + when (type) { + ViewType.SEMESTER -> gradeStatisticsRepository.getGradesStatistics(student, semester, subjectName, true, forceRefresh) + ViewType.PARTIAL -> gradeStatisticsRepository.getGradesStatistics(student, semester, subjectName, false, forceRefresh) + ViewType.POINTS -> gradeStatisticsRepository.getGradesPointsStatistics(student, semester, subjectName, forceRefresh) + } } } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index 5f4412773..c12f2a516 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -38,7 +38,7 @@ class GradeSummaryPresenter @Inject constructor( disposable.add(studentRepository.getCurrentStudent() .flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } } .flatMap { (student, semesters) -> - gradeSummaryRepository.getGradesSummary(semesters.first { it.semesterId == semesterId }, forceRefresh) + gradeSummaryRepository.getGradesSummary(student, semesters.first { it.semesterId == semesterId }, forceRefresh) .map { it.sortedBy { subject -> subject.subject } } .flatMap { gradesSummary -> averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt index 26d16b1df..aae18df32 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/homework/HomeworkPresenter.kt @@ -105,9 +105,12 @@ class HomeworkPresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + homeworkRepository.getHomework(student, semester, currentDate, currentDate, forceRefresh) + } + } .delay(200, TimeUnit.MILLISECONDS) - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { homeworkRepository.getHomework(it, currentDate, currentDate, forceRefresh) } .map { it.groupBy { homework -> homework.date }.toSortedMap() } .map { createHomeworkItem(it) } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt index 5a19d9fab..62ac5a532 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/preview/MessagePreviewPresenter.kt @@ -85,7 +85,8 @@ class MessagePreviewPresenter @Inject constructor( private fun deleteMessage() { message?.let { message -> - disposable.add(messageRepository.deleteMessage(message) + disposable.add(studentRepository.getCurrentStudent() + .flatMap { messageRepository.deleteMessage(it, message) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doOnSubscribe { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt index 3b89b5cae..385c12ff7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/message/send/SendMessagePresenter.kt @@ -148,7 +148,8 @@ class SendMessagePresenter @Inject constructor( private fun sendMessage(subject: String, content: String, recipients: List) { Timber.i("Sending message started") - disposable.add(messageRepository.sendMessage(subject, content, recipients) + disposable.add(studentRepository.getCurrentStudent() + .flatMap { messageRepository.sendMessage(it, subject, content, recipients) } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doOnSubscribe { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt index e95d2ce0e..a6a83f8a9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/MobileDevicePresenter.kt @@ -49,8 +49,11 @@ class MobileDevicePresenter @Inject constructor( private fun loadData(forceRefresh: Boolean = false) { Timber.i("Loading mobile devices data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { mobileDeviceRepository.getDevices(it, forceRefresh) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + mobileDeviceRepository.getDevices(student, semester, forceRefresh) + } + } .map { items -> items.map { MobileDeviceItem(it) } } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) @@ -107,10 +110,11 @@ class MobileDevicePresenter @Inject constructor( fun onUnregisterConfirmed(device: MobileDevice) { Timber.i("Unregister device started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { semester -> - mobileDeviceRepository.unregisterDevice(semester, device) - .flatMap { mobileDeviceRepository.getDevices(semester, it) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + mobileDeviceRepository.unregisterDevice(student, semester, device) + .flatMap { mobileDeviceRepository.getDevices(student, semester, it) } + } } .map { items -> items.map { MobileDeviceItem(it) } } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt index a778cbeda..6a2a6b98b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/mobiledevice/token/MobileDeviceTokenPresenter.kt @@ -29,8 +29,11 @@ class MobileDeviceTokenPresenter @Inject constructor( private fun loadData() { Timber.i("Mobile device registration data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { mobileDeviceRepository.getToken(it) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + mobileDeviceRepository.getToken(student, semester) + } + } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { view?.hideLoading() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt index d3299d90d..e2eb614dc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/school/SchoolPresenter.kt @@ -64,8 +64,11 @@ class SchoolPresenter @Inject constructor( private fun loadData(forceRefresh: Boolean = false) { Timber.i("Loading school info started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMapMaybe { schoolRepository.getSchoolInfo(it, forceRefresh) } + .flatMapMaybe { student -> + semesterRepository.getCurrentSemester(student).flatMapMaybe { + schoolRepository.getSchoolInfo(student, it, forceRefresh) + } + } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt index 6aa4871d2..c5b6cfd69 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/schoolandteachers/teacher/TeacherPresenter.kt @@ -52,8 +52,11 @@ class TeacherPresenter @Inject constructor( private fun loadData(forceRefresh: Boolean = false) { Timber.i("Loading teachers data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } - .flatMap { teacherRepository.getTeachers(it, forceRefresh) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + teacherRepository.getTeachers(student, semester, forceRefresh) + } + } .map { it.filter { teacher -> teacher.name.isNotBlank() } } .map { items -> items.map { TeacherItem(it, view?.noSubjectString.orEmpty()) } } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt index 913f6c121..2e9d0a0b3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/TimetablePresenter.kt @@ -134,9 +134,12 @@ class TimetablePresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + timetableRepository.getTimetable(student, semester, currentDate, currentDate, forceRefresh) + } + } .delay(200, MILLISECONDS) - .flatMap { timetableRepository.getTimetable(it, currentDate, currentDate, forceRefresh) } .map { createTimetableItems(it) } .map { items -> items.sortedWith(compareBy({ it.lesson.number }, { !it.lesson.isStudentPlan })) } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt index e2b569508..001fed97b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetable/completed/CompletedLessonsPresenter.kt @@ -114,9 +114,12 @@ class CompletedLessonsPresenter @Inject constructor( disposable.apply { clear() add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getCurrentSemester(it) } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).flatMap { semester -> + completedLessonsRepository.getCompletedLessons(student, semester, currentDate, currentDate, forceRefresh) + } + } .delay(200, TimeUnit.MILLISECONDS) - .flatMap { completedLessonsRepository.getCompletedLessons(it, currentDate, currentDate, forceRefresh) } .map { items -> items.map { CompletedLessonItem(it) } } .map { items -> items.sortedBy { it.completedLesson.number } } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt index 62620b8ed..fb8c59586 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/timetablewidget/TimetableWidgetFactory.kt @@ -107,8 +107,11 @@ class TimetableWidgetFactory( if (student != null) Maybe.just(student) else Maybe.empty() } - .flatMap { semesterRepository.getCurrentSemester(it).toMaybe() } - .flatMap { timetableRepository.getTimetable(it, date, date).toMaybe() } + .flatMap { student -> + semesterRepository.getCurrentSemester(student).toMaybe().flatMap { semester -> + timetableRepository.getTimetable(student, semester, date, date).toMaybe() + } + } .map { items -> items.sortedWith(compareBy({ it.number }, { !it.isStudentPlan })) } .map { lessons -> lessons.filter { if (prefRepository.showWholeClassPlan == "no") it.isStudentPlan else true } } .subscribeOn(schedulers.backgroundThread) diff --git a/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt new file mode 100644 index 000000000..e4d4163b4 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/SdkExtension.kt @@ -0,0 +1,29 @@ +package io.github.wulkanowy.utils + +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.sdk.Sdk +import timber.log.Timber + +fun Sdk.init(student: Student): Sdk { + email = student.email + password = student.password + symbol = student.symbol + schoolSymbol = student.schoolSymbol + studentId = student.studentId + classId = student.classId + + if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) { + scrapperBaseUrl = student.scrapperBaseUrl + loginType = Sdk.ScrapperLoginType.valueOf(student.loginType) + } + loginId = student.userLoginId + + mode = Sdk.Mode.valueOf(student.loginMode) + mobileBaseUrl = student.mobileBaseUrl + certKey = student.certificateKey + privateKey = student.privateKey + + Timber.d("Sdk in ${student.loginMode} mode reinitialized") + + return this +} diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/TestEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/TestEnityCreator.kt new file mode 100644 index 000000000..175242bb8 --- /dev/null +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/TestEnityCreator.kt @@ -0,0 +1,47 @@ +package io.github.wulkanowy.data.repositories + +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.sdk.Sdk +import org.threeten.bp.LocalDate +import org.threeten.bp.LocalDateTime.now + +fun createSemesterEntity(diaryId: Int, semesterId: Int, start: LocalDate, end: LocalDate, semesterName: Int = 1): Semester { + return Semester( + studentId = 1, + diaryId = diaryId, + semesterId = semesterId, + diaryName = "$semesterId", + schoolYear = 1970, + classId = 0, + semesterName = semesterName, + unitId = 1, + start = start, + end = end + ) +} + +fun getStudentEntity(mode: Sdk.Mode = Sdk.Mode.API): Student { + return Student( + scrapperBaseUrl = "http://fakelog.cf", + email = "jan@fakelog.cf", + certificateKey = "", + classId = 0, + className = "", + isCurrent = false, + isParent = false, + loginMode = mode.name, + loginType = "STANDARD", + mobileBaseUrl = "", + password = "", + privateKey = "", + registrationDate = now(), + schoolName = "", + schoolShortName = "test", + schoolSymbol = "", + studentId = 0, + studentName = "", + symbol = "", + userLoginId = 0 + ) +} diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemoteTest.kt index b471dc520..b684ffc5f 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/attendance/AttendanceRemoteTest.kt @@ -1,11 +1,15 @@ package io.github.wulkanowy.data.repositories.attendance import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.repositories.getStudentEntity import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Attendance +import io.github.wulkanowy.utils.init import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.SpyK import io.reactivex.Single import org.junit.Assert.assertEquals import org.junit.Before @@ -15,12 +19,14 @@ import org.threeten.bp.LocalDate.of class AttendanceRemoteTest { - @MockK - private lateinit var mockSdk: Sdk + @SpyK + private var mockSdk = Sdk() @MockK private lateinit var semesterMock: Semester + private var student = getStudentEntity() + @Before fun initApi() { MockKAnnotations.init(this) @@ -28,6 +34,7 @@ class AttendanceRemoteTest { @Test fun getAttendanceTest() { + every { mockSdk.init(student) } returns mockSdk every { mockSdk.getAttendance( of(2018, 9, 10), @@ -45,7 +52,7 @@ class AttendanceRemoteTest { every { semesterMock.semesterId } returns 1 every { mockSdk.switchDiary(any(), any()) } returns mockSdk - val attendance = AttendanceRemote(mockSdk).getAttendance(semesterMock, + val attendance = AttendanceRemote(mockSdk).getAttendance(student, semesterMock, of(2018, 9, 10), of(2018, 9, 15) ).blockingGet() diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemoteTest.kt index 7570164fd..6a93067f2 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/completedlessons/CompletedLessonsRemoteTest.kt @@ -1,11 +1,14 @@ package io.github.wulkanowy.data.repositories.completedlessons import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.getStudentEntity import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.CompletedLesson +import io.github.wulkanowy.utils.init import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.SpyK import io.reactivex.Single import org.junit.Assert import org.junit.Before @@ -15,12 +18,14 @@ import org.threeten.bp.LocalDate.of class CompletedLessonsRemoteTest { - @MockK - private lateinit var mockSdk: Sdk + @SpyK + private var mockSdk = Sdk() @MockK private lateinit var semesterMock: Semester + private val student = getStudentEntity() + @Before fun initApi() { MockKAnnotations.init(this) @@ -28,6 +33,7 @@ class CompletedLessonsRemoteTest { @Test fun getCompletedLessonsTest() { + every { mockSdk.init(student) } returns mockSdk every { mockSdk.getCompletedLessons( of(2018, 9, 10), @@ -44,7 +50,7 @@ class CompletedLessonsRemoteTest { every { semesterMock.semesterId } returns 1 every { mockSdk.switchDiary(any(), any()) } returns mockSdk - val completed = CompletedLessonsRemote(mockSdk).getCompletedLessons(semesterMock, + val completed = CompletedLessonsRemote(mockSdk).getCompletedLessons(student, semesterMock, of(2018, 9, 10), of(2018, 9, 15) ).blockingGet() diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/exam/ExamRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/exam/ExamRemoteTest.kt index c17ec21eb..d2b06af78 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/exam/ExamRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/exam/ExamRemoteTest.kt @@ -1,11 +1,14 @@ package io.github.wulkanowy.data.repositories.exam import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.getStudentEntity import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Exam +import io.github.wulkanowy.utils.init import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.SpyK import io.reactivex.Single import org.junit.Assert.assertEquals import org.junit.Before @@ -15,19 +18,24 @@ import org.threeten.bp.LocalDate.of class ExamRemoteTest { - @MockK - private lateinit var mockSdk: Sdk + @SpyK + private var mockSdk = Sdk() @MockK private lateinit var semesterMock: Semester + private val student = getStudentEntity() + @Before - fun initApi() { + fun setUp() { MockKAnnotations.init(this) } @Test fun getExamsTest() { + every { mockSdk.init(student) } returns mockSdk + every { mockSdk.switchDiary(1, 2019) } returns mockSdk + every { mockSdk.getExams( of(2018, 9, 10), @@ -43,13 +51,11 @@ class ExamRemoteTest { every { semesterMock.diaryId } returns 1 every { semesterMock.schoolYear } returns 2019 every { semesterMock.semesterId } returns 1 - every { mockSdk.switchDiary(any(), any()) } returns mockSdk - val exams = ExamRemote(mockSdk) - .getExams(semesterMock, - of(2018, 9, 10), - of(2018, 9, 15) - ).blockingGet() + val exams = ExamRemote(mockSdk).getExams(student, semesterMock, + of(2018, 9, 10), + of(2018, 9, 15) + ).blockingGet() assertEquals(2, exams.size) } diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemoteTest.kt index ee08454f1..7e481ee47 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/gradestatistics/GradeStatisticsRemoteTest.kt @@ -1,12 +1,15 @@ package io.github.wulkanowy.data.repositories.gradestatistics import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.getStudentEntity import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.GradePointsStatistics import io.github.wulkanowy.sdk.pojo.GradeStatistics +import io.github.wulkanowy.utils.init import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.SpyK import io.reactivex.Single import org.junit.Assert.assertEquals import org.junit.Before @@ -14,15 +17,18 @@ import org.junit.Test class GradeStatisticsRemoteTest { - @MockK - private lateinit var mockSdk: Sdk + @SpyK + private var mockSdk = Sdk() @MockK private lateinit var semesterMock: Semester + private val student = getStudentEntity() + @Before fun initApi() { MockKAnnotations.init(this) + every { mockSdk.init(student) } returns mockSdk } @Test @@ -38,7 +44,7 @@ class GradeStatisticsRemoteTest { every { semesterMock.semesterId } returns 1 every { mockSdk.switchDiary(any(), any()) } returns mockSdk - val stats = GradeStatisticsRemote(mockSdk).getGradeStatistics(semesterMock, false).blockingGet() + val stats = GradeStatisticsRemote(mockSdk).getGradeStatistics(student, semesterMock, false).blockingGet() assertEquals(2, stats.size) } @@ -55,7 +61,7 @@ class GradeStatisticsRemoteTest { every { semesterMock.semesterId } returns 1 every { mockSdk.switchDiary(any(), any()) } returns mockSdk - val stats = GradeStatisticsRemote(mockSdk).getGradePointsStatistics(semesterMock).blockingGet() + val stats = GradeStatisticsRemote(mockSdk).getGradePointsStatistics(student, semesterMock).blockingGet() assertEquals(2, stats.size) } diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemoteTest.kt index 79bd26f8a..904e8c18c 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/luckynumber/LuckyNumberRemoteTest.kt @@ -1,10 +1,10 @@ package io.github.wulkanowy.data.repositories.luckynumber -import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.repositories.getStudentEntity import io.github.wulkanowy.sdk.Sdk +import io.github.wulkanowy.utils.init import io.mockk.MockKAnnotations import io.mockk.every -import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.SpyK import io.reactivex.Maybe import org.junit.Assert.assertEquals @@ -17,28 +17,26 @@ class LuckyNumberRemoteTest { @SpyK private var mockSdk = Sdk() - @MockK - private lateinit var studentMock: Student + private val student = getStudentEntity(Sdk.Mode.SCRAPPER) @Before - fun initApi() { + fun setUp() { MockKAnnotations.init(this) } @Test fun getLuckyNumberTest() { + every { mockSdk.init(student) } returns mockSdk every { mockSdk.getLuckyNumber("test") } returns Maybe.just(14) every { mockSdk.diaryId } returns 1 - every { studentMock.studentId } returns 1 - every { studentMock.schoolShortName } returns "test" val luckyNumber = LuckyNumberRemote(mockSdk) - .getLuckyNumber(studentMock) + .getLuckyNumber(student) .blockingGet() assertEquals(14, luckyNumber.luckyNumber) assertEquals(LocalDate.now(), luckyNumber.date) - assertEquals(studentMock.studentId, luckyNumber.studentId) + assertEquals(student.studentId, luckyNumber.studentId) } } diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt index b540c9e5f..b7963d430 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/message/MessageRepositoryTest.kt @@ -2,7 +2,6 @@ package io.github.wulkanowy.data.repositories.message import androidx.room.EmptyResultSetException import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.MessageWithAttachment import io.github.wulkanowy.data.db.entities.Student @@ -21,9 +20,6 @@ import java.net.UnknownHostException class MessageRepositoryTest { - @Mock - lateinit var sdk: SdkHelper - @Mock lateinit var local: MessageLocal @@ -43,7 +39,7 @@ class MessageRepositoryTest { repo = MessageRepository(InternetObservingSettings.builder() .strategy(testObservingStrategy) - .build(), local, remote, sdk) + .build(), local, remote) } @Test @@ -80,7 +76,7 @@ class MessageRepositoryTest { `when`(local.getMessageWithAttachment(student, testMessage)) .thenReturn(Single.just(mWa)) .thenReturn(Single.just(mWaWithContent)) - `when`(remote.getMessagesContentDetails(testMessageWithContent)).thenReturn(Single.just("Test" to emptyList())) + `when`(remote.getMessagesContentDetails(student, testMessageWithContent)).thenReturn(Single.just("Test" to emptyList())) val message = repo.getMessage(student, testMessage).blockingGet() diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepositoryTest.kt index 9c1bb9756..adfa55eaa 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/mobiledevice/MobileDeviceRepositoryTest.kt @@ -4,6 +4,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.repositories.UnitTestInternetObservingStrategy +import io.github.wulkanowy.data.repositories.getStudentEntity import io.reactivex.Maybe import io.reactivex.Single import org.junit.Before @@ -25,6 +26,8 @@ class MobileDeviceRepositoryTest { @Mock private lateinit var mobileDeviceLocal: MobileDeviceLocal + private val student = getStudentEntity() + private lateinit var mobileDeviceRepository: MobileDeviceRepository private val settings = InternetObservingSettings.builder() @@ -45,9 +48,9 @@ class MobileDeviceRepositoryTest { ) doReturn(Maybe.empty()).`when`(mobileDeviceLocal).getDevices(semester) - doReturn(Single.just(devices)).`when`(mobileDeviceRemote).getDevices(semester) + doReturn(Single.just(devices)).`when`(mobileDeviceRemote).getDevices(student, semester) - mobileDeviceRepository.getDevices(semester).blockingGet() + mobileDeviceRepository.getDevices(student, semester).blockingGet() verify(mobileDeviceLocal).deleteDevices(emptyList()) verify(mobileDeviceLocal).saveDevices(devices) diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/semester/SemesterRepositoryTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/semester/SemesterRepositoryTest.kt index 7363c30f9..af872c577 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/semester/SemesterRepositoryTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/semester/SemesterRepositoryTest.kt @@ -1,17 +1,16 @@ package io.github.wulkanowy.data.repositories.semester import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings -import io.github.wulkanowy.data.SdkHelper import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.UnitTestInternetObservingStrategy +import io.github.wulkanowy.data.repositories.createSemesterEntity import io.reactivex.Maybe import io.reactivex.Single import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.mockito.Mock -import org.mockito.Mockito.doNothing import org.mockito.Mockito.doReturn import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -25,9 +24,6 @@ class SemesterRepositoryTest { @Mock private lateinit var semesterLocal: SemesterLocal - @Mock - private lateinit var sdkHelper: SdkHelper - @Mock private lateinit var student: Student @@ -40,7 +36,7 @@ class SemesterRepositoryTest { @Before fun initTest() { MockitoAnnotations.initMocks(this) - semesterRepository = SemesterRepository(semesterRemote, semesterLocal, settings, sdkHelper) + semesterRepository = SemesterRepository(semesterRemote, semesterLocal, settings) } @Test @@ -50,7 +46,6 @@ class SemesterRepositoryTest { createSemesterEntity(0, 0, now().minusMonths(3), now()) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.empty()).`when`(semesterLocal).getSemesters(student) doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student) @@ -64,10 +59,9 @@ class SemesterRepositoryTest { fun getSemesters_noCurrent() { val semesters = listOf( createSemesterEntity(0, 0, now().minusMonths(12), now().minusMonths(6)), - createSemesterEntity(0, 0, now().minusMonths( 6), now().minusMonths(1)) + createSemesterEntity(0, 0, now().minusMonths(6), now().minusMonths(1)) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(semesters)).`when`(semesterLocal).getSemesters(student) val items = semesterRepository.getSemesters(student).blockingGet() @@ -81,7 +75,6 @@ class SemesterRepositoryTest { createSemesterEntity(0, 0, now().minusMonths(3), now()) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(semesters)).`when`(semesterLocal).getSemesters(student) val items = semesterRepository.getSemesters(student).blockingGet() @@ -95,7 +88,6 @@ class SemesterRepositoryTest { createSemesterEntity(0, 0, now(), now()) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(semesters)).`when`(semesterLocal).getSemesters(student) val items = semesterRepository.getSemesters(student).blockingGet() @@ -109,7 +101,6 @@ class SemesterRepositoryTest { createSemesterEntity(0, 0, now().minusMonths(3), now()) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.empty()).`when`(semesterLocal).getSemesters(student) doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student) @@ -123,10 +114,9 @@ class SemesterRepositoryTest { fun getSemesters_noCurrent_refreshOnNoCurrent() { val semesters = listOf( createSemesterEntity(0, 0, now().minusMonths(12), now().minusMonths(6)), - createSemesterEntity(0, 0, now().minusMonths( 6), now().minusMonths(1)) + createSemesterEntity(0, 0, now().minusMonths(6), now().minusMonths(1)) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(semesters)).`when`(semesterLocal).getSemesters(student) doReturn(Single.just(semesters)).`when`(semesterRemote).getSemesters(student) @@ -141,7 +131,6 @@ class SemesterRepositoryTest { createSemesterEntity(0, 0, now(), now()) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(semesters)).`when`(semesterLocal).getSemesters(student) val items = semesterRepository.getSemesters(student, refreshOnNoCurrent = true).blockingGet() @@ -155,7 +144,6 @@ class SemesterRepositoryTest { createSemesterEntity(0, 0, now(), now()) ) - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(semesters)).`when`(semesterLocal).getSemesters(student) semesterRepository.getCurrentSemester(student).blockingGet() @@ -163,7 +151,6 @@ class SemesterRepositoryTest { @Test(expected = RuntimeException::class) fun getCurrentSemester_emptyList() { - doNothing().`when`(sdkHelper).init(student) doReturn(Maybe.just(emptyList())).`when`(semesterLocal).getSemesters(student) semesterRepository.getCurrentSemester(student).blockingGet() diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/semester/TestSemesterEnityCreator.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/semester/TestSemesterEnityCreator.kt deleted file mode 100644 index fc90135f9..000000000 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/semester/TestSemesterEnityCreator.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.wulkanowy.data.repositories.semester - -import io.github.wulkanowy.data.db.entities.Semester -import org.threeten.bp.LocalDate - -fun createSemesterEntity(diaryId: Int, semesterId: Int, start: LocalDate, end: LocalDate, semesterName: Int = 1): Semester { - return Semester( - studentId = 1, - diaryId = diaryId, - semesterId = semesterId, - diaryName = "$semesterId", - schoolYear = 1970, - classId = 0, - semesterName = semesterName, - unitId = 1, - start = start, - end = end - ) -} diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt index 100bc0aed..c4548db60 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/timetable/TimetableRemoteTest.kt @@ -1,11 +1,13 @@ package io.github.wulkanowy.data.repositories.timetable import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.getStudentEntity import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.pojo.Timetable import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.impl.annotations.SpyK import io.reactivex.Single import org.junit.Assert.assertEquals import org.junit.Before @@ -16,12 +18,14 @@ import org.threeten.bp.LocalDateTime.now class TimetableRemoteTest { - @MockK - private lateinit var mockSdk: Sdk + @SpyK + private var mockSdk = Sdk() @MockK private lateinit var semesterMock: Semester + private val student = getStudentEntity() + @Before fun initApi() { MockKAnnotations.init(this) @@ -45,7 +49,7 @@ class TimetableRemoteTest { every { semesterMock.semesterId } returns 1 every { mockSdk.switchDiary(any(), any()) } returns mockSdk - val timetable = TimetableRemote(mockSdk).getTimetable(semesterMock, + val timetable = TimetableRemote(mockSdk).getTimetable(student, semesterMock, of(2018, 9, 10), of(2018, 9, 15) ).blockingGet() diff --git a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt index 481aff78a..009ed610e 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProviderTest.kt @@ -6,7 +6,7 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.grade.GradeRepository import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository -import io.github.wulkanowy.data.repositories.semester.createSemesterEntity +import io.github.wulkanowy.data.repositories.createSemesterEntity import io.github.wulkanowy.sdk.Sdk import io.reactivex.Single import org.junit.Assert.assertEquals @@ -75,7 +75,7 @@ class GradeAverageProviderTest { @Test fun onlyOneSemesterTest() { doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) .blockingGet() @@ -88,7 +88,7 @@ class GradeAverageProviderTest { @Test fun onlyOneSemester_gradesWithModifiers_default() { doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student, semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) @@ -100,7 +100,7 @@ class GradeAverageProviderTest { @Test fun onlyOneSemester_gradesWithModifiers_api() { doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student.copy(loginMode = Sdk.Mode.API.name), semesters[2], true) doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.API.name), semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.API.name), semesters, semesters[2].semesterId, true) @@ -112,7 +112,7 @@ class GradeAverageProviderTest { @Test fun onlyOneSemester_gradesWithModifiers_scrapper() { doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.SCRAPPER.name), semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.SCRAPPER.name), semesters, semesters[2].semesterId, true) @@ -124,7 +124,7 @@ class GradeAverageProviderTest { @Test fun onlyOneSemester_gradesWithModifiers_hybrid() { doReturn("only_one_semester").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters[2], true) doReturn(Single.just(secondGradeWithModifier)).`when`(gradeRepository).getGrades(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student.copy(loginMode = Sdk.Mode.HYBRID.name), semesters, semesters[2].semesterId, true) @@ -136,7 +136,7 @@ class GradeAverageProviderTest { @Test fun allYearFirstSemesterTest() { doReturn("all_year").`when`(preferencesRepository).gradeAverageMode - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[1], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[1], true) val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[1].semesterId, true) .blockingGet() @@ -150,7 +150,7 @@ class GradeAverageProviderTest { fun allYearSecondSemesterTest() { doReturn("all_year").`when`(preferencesRepository).gradeAverageMode doReturn(Single.just(firstGrades)).`when`(gradeRepository).getGrades(student, semesters[1], false) - doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + doReturn(Single.just(emptyList())).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) .blockingGet() @@ -174,7 +174,7 @@ class GradeAverageProviderTest { doReturn(Single.just(listOf( getSummary(22, "Matematyka", 3.1), getSummary(22, "Fizyka", 3.26) - ))).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + ))).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) .blockingGet() @@ -192,7 +192,7 @@ class GradeAverageProviderTest { doReturn(Single.just(listOf( getSummary(22, "Matematyka", 3.1), getSummary(22, "Fizyka", 3.26) - ))).`when`(gradeSummaryRepository).getGradesSummary(semesters[2], true) + ))).`when`(gradeSummaryRepository).getGradesSummary(student, semesters[2], true) val averages = gradeAverageProvider.getGradeAverage(student, semesters, semesters[2].semesterId, true) .blockingGet() From 64a19d9627c5c2d2b1260d7439acc40c8ebfa866 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2020 15:14:08 +0000 Subject: [PATCH 44/61] Bump about_libraries from 8.1.0 to 8.1.1 (#769) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 47a365b6c..3facb0451 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext.kotlin_version = '1.3.71' - ext.about_libraries = '8.1.0' + ext.about_libraries = '8.1.1' repositories { mavenCentral() google() From 3ac085573f67a3d31e8202a687a9fdc9555702d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 12 Apr 2020 18:55:16 +0200 Subject: [PATCH 45/61] Show all known adfslight registers in register list (#766) --- .../modules/login/form/LoginFormFragment.kt | 34 +- .../modules/login/form/LoginFormPresenter.kt | 23 +- .../ui/modules/login/form/LoginFormView.kt | 10 - .../login/recover/LoginRecoverFragment.kt | 28 +- .../login/recover/LoginRecoverPresenter.kt | 18 +- .../modules/login/recover/LoginRecoverView.kt | 10 +- .../main/res/layout/fragment_login_form.xml | 36 +- .../res/layout/fragment_login_recover.xml | 36 +- app/src/main/res/values/api_hosts.xml | 35 +- app/src/main/res/values/api_symbols.xml | 358 +++++++++++++++++- .../login/form/LoginFormPresenterTest.kt | 4 - 11 files changed, 397 insertions(+), 195 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index 999ec22ab..058e702e6 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -7,7 +7,6 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import android.view.ViewGroup -import android.widget.ArrayAdapter import androidx.core.widget.doOnTextChanged import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Student @@ -46,9 +45,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView { override val formHostSymbol: String get() = hostSymbols.getOrNull(hostKeys.indexOf(loginFormHost.text.toString())).orEmpty() - override val formSymbolValue: String - get() = loginFormSymbol.text.toString() - override val nicknameLabel: String get() = getString(R.string.login_nickname_hint) @@ -77,7 +73,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView { loginFormUsername.doOnTextChanged { _, _, _, _ -> presenter.onUsernameTextChanged() } loginFormPass.doOnTextChanged { _, _, _, _ -> presenter.onPassTextChanged() } - loginFormSymbol.doOnTextChanged { _, _, _, _ -> presenter.onSymbolTextChanged() } loginFormHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() } loginFormSignIn.setOnClickListener { presenter.onSignInClick() } loginFormAdvancedButton.setOnClickListener { presenter.onAdvancedLoginClick() } @@ -86,9 +81,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView { loginFormContactEmail.setOnClickListener { presenter.onEmailClick() } loginFormRecoverLink.setOnClickListener { presenter.onRecoverClick() } loginFormPass.setOnEditorDoneSignIn { loginFormSignIn.callOnClick() } - loginFormSymbol.setOnEditorDoneSignIn { loginFormSignIn.callOnClick() } - - loginFormSymbol.setAdapter(ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values))) with(loginFormHost) { setText(hostKeys.getOrNull(0).orEmpty()) @@ -102,18 +94,10 @@ class LoginFormFragment : BaseFragment(), LoginFormView { loginFormPass.setText(pass) } - override fun setSymbol(symbol: String) { - loginFormSymbol.setText(symbol) - } - override fun setUsernameLabel(label: String) { loginFormUsernameLayout.hint = label } - override fun showSymbol(show: Boolean) { - loginFormSymbolLayout.visibility = if (show) VISIBLE else GONE - } - override fun setErrorUsernameRequired() { with(loginFormUsernameLayout) { requestFocus() @@ -135,13 +119,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView { } } - override fun setErrorSymbolRequired(focus: Boolean) { - with(loginFormSymbolLayout) { - if (focus) requestFocus() - error = getString(R.string.login_symbol_helper) - } - } - override fun setErrorPassRequired(focus: Boolean) { with(loginFormPassLayout) { if (focus) requestFocus() @@ -171,10 +148,6 @@ class LoginFormFragment : BaseFragment(), LoginFormView { loginFormPassLayout.error = null } - override fun clearSymbolError() { - loginFormSymbolLayout.error = null - } - override fun showSoftKeyboard() { activity?.showSoftInput() } @@ -227,10 +200,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView { override fun onResume() { super.onResume() - with(presenter) { - updateUsernameLabel() - updateSymbolInputVisibility() - } + presenter.updateUsernameLabel() } override fun openEmail(lastError: String) { @@ -242,7 +212,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView { "${appInfo.systemManufacturer} ${appInfo.systemModel}", appInfo.systemVersion.toString(), appInfo.versionName, - "$formHostValue/$formSymbolValue", + "$formHostValue/$formHostSymbol", lastError ) ) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index e566d3d6b..997e1e85f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -48,9 +48,7 @@ class LoginFormPresenter @Inject constructor( if (formHostValue.contains("fakelog")) { setCredentials("jan@fakelog.cf", "jan123") } - setSymbol(formHostSymbol) updateUsernameLabel() - updateSymbolInputVisibility() } } @@ -60,12 +58,6 @@ class LoginFormPresenter @Inject constructor( } } - fun updateSymbolInputVisibility() { - view?.run { - showSymbol("adfs" in formHostValue) - } - } - fun onPassTextChanged() { view?.clearPassError() } @@ -74,17 +66,13 @@ class LoginFormPresenter @Inject constructor( view?.clearUsernameError() } - fun onSymbolTextChanged() { - view?.clearSymbolError() - } - fun onSignInClick() { val email = view?.formUsernameValue.orEmpty().trim() val password = view?.formPassValue.orEmpty().trim() val host = view?.formHostValue.orEmpty().trim() - val symbol = view?.formSymbolValue.orEmpty().trim() + val symbol = view?.formHostSymbol.orEmpty().trim() - if (!validateCredentials(email, password, host, symbol)) return + if (!validateCredentials(email, password, host)) return disposable.add(studentRepository.getStudentsScrapper(email, password, host, symbol) .subscribeOn(schedulers.backgroundThread) @@ -128,7 +116,7 @@ class LoginFormPresenter @Inject constructor( view?.onRecoverClick() } - private fun validateCredentials(login: String, password: String, host: String, symbol: String): Boolean { + private fun validateCredentials(login: String, password: String, host: String): Boolean { var isCorrect = true if (login.isEmpty()) { @@ -156,11 +144,6 @@ class LoginFormPresenter @Inject constructor( isCorrect = false } - if ("standard" !in host && symbol.isBlank()) { - view?.setErrorSymbolRequired(focus = isCorrect) - isCorrect = false - } - return isCorrect } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt index 8e46f93fd..6506fa88f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormView.kt @@ -15,28 +15,20 @@ interface LoginFormView : BaseView { val formHostSymbol: String - val formSymbolValue: String - val nicknameLabel: String val emailLabel: String fun setCredentials(username: String, pass: String) - fun setSymbol(symbol: String) - fun setUsernameLabel(label: String) - fun showSymbol(show: Boolean) - fun setErrorUsernameRequired() fun setErrorLoginRequired() fun setErrorEmailRequired() - fun setErrorSymbolRequired(focus: Boolean) - fun setErrorPassRequired(focus: Boolean) fun setErrorPassInvalid(focus: Boolean) @@ -47,8 +39,6 @@ interface LoginFormView : BaseView { fun clearPassError() - fun clearSymbolError() - fun showSoftKeyboard() fun hideSoftKeyboard() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt index 6e8a83c73..1bff49262 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverFragment.kt @@ -11,7 +11,6 @@ import android.view.ViewGroup import android.webkit.JavascriptInterface import android.webkit.WebView import android.webkit.WebViewClient -import android.widget.ArrayAdapter import androidx.core.widget.doOnTextChanged import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseFragment @@ -35,15 +34,17 @@ class LoginRecoverFragment : BaseFragment(), LoginRecoverView { private lateinit var hostValues: Array + private lateinit var hostSymbols: Array + override val recoverHostValue: String get() = hostValues.getOrNull(hostKeys.indexOf(loginRecoverHost.text.toString())).orEmpty() + override val formHostSymbol: String + get() = hostSymbols.getOrNull(hostKeys.indexOf(loginRecoverHost.text.toString())).orEmpty() + override val recoverNameValue: String get() = loginRecoverName.text.toString().trim() - override val recoverSymbolValue: String - get() = loginRecoverSymbol.text.toString().trim() - override val emailHintString: String get() = getString(R.string.login_email_hint) @@ -66,17 +67,15 @@ class LoginRecoverFragment : BaseFragment(), LoginRecoverView { loginRecoverWebView.setBackgroundColor(Color.TRANSPARENT) hostKeys = resources.getStringArray(R.array.hosts_keys) hostValues = resources.getStringArray(R.array.hosts_values) + hostSymbols = resources.getStringArray(R.array.hosts_symbols) loginRecoverName.doOnTextChanged { _, _, _, _ -> presenter.onNameTextChanged() } - loginRecoverSymbol.doOnTextChanged { _, _, _, _ -> presenter.onSymbolTextChanged() } loginRecoverHost.setOnItemClickListener { _, _, _, _ -> presenter.onHostSelected() } loginRecoverButton.setOnClickListener { presenter.onRecoverClick() } loginRecoverErrorRetry.setOnClickListener { presenter.onRecoverClick() } loginRecoverErrorDetails.setOnClickListener { presenter.onDetailsClick() } loginRecoverLogin.setOnClickListener { (activity as LoginActivity).switchView(0) } - loginRecoverSymbol.setAdapter(ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values))) - with(loginRecoverHost) { setText(hostKeys.getOrNull(0).orEmpty()) setAdapter(LoginSymbolAdapter(context, R.layout.support_simple_spinner_dropdown_item, hostKeys)) @@ -106,25 +105,10 @@ class LoginRecoverFragment : BaseFragment(), LoginRecoverView { } } - override fun setSymbolError(focus: Boolean) { - with(loginRecoverSymbolLayout) { - if (focus) requestFocus() - error = getString(R.string.login_field_required) - } - } - override fun clearUsernameError() { loginRecoverNameLayout.error = null } - override fun clearSymbolError() { - loginRecoverSymbolLayout.error = null - } - - override fun showSymbol(show: Boolean) { - loginRecoverSymbolLayout.visibility = if (show) VISIBLE else GONE - } - override fun showProgress(show: Boolean) { loginRecoverProgress.visibility = if (show) VISIBLE else GONE } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt index 7016d1734..b292ded53 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverPresenter.kt @@ -34,10 +34,6 @@ class LoginRecoverPresenter @Inject constructor( view?.clearUsernameError() } - fun onSymbolTextChanged() { - view?.clearSymbolError() - } - fun onHostSelected() { view?.run { if ("fakelog" in recoverHostValue) setDefaultCredentials("jan@fakelog.cf") @@ -48,7 +44,6 @@ class LoginRecoverPresenter @Inject constructor( fun updateFields() { view?.run { - showSymbol("adfs" in recoverHostValue) setUsernameHint(if ("standard" in recoverHostValue) emailHintString else loginPeselEmailHintString) } } @@ -56,9 +51,9 @@ class LoginRecoverPresenter @Inject constructor( fun onRecoverClick() { val username = view?.recoverNameValue.orEmpty() val host = view?.recoverHostValue.orEmpty() - val symbol = view?.recoverSymbolValue.orEmpty() + val symbol = view?.formHostSymbol.orEmpty() - if (!validateInput(username, host, symbol)) return + if (!validateInput(username, host)) return disposable.add(recoverRepository.getReCaptchaSiteKey(host, symbol.ifBlank { "Default" }) .subscribeOn(schedulers.backgroundThread) @@ -80,7 +75,7 @@ class LoginRecoverPresenter @Inject constructor( }) } - private fun validateInput(username: String, host: String, symbol: String): Boolean { + private fun validateInput(username: String, host: String): Boolean { var isCorrect = true if (username.isEmpty()) { @@ -93,18 +88,13 @@ class LoginRecoverPresenter @Inject constructor( isCorrect = false } - if ("adfs" in host && symbol.isBlank()) { - view?.setSymbolError(focus = isCorrect) - isCorrect = false - } - return isCorrect } fun onReCaptchaVerified(reCaptchaResponse: String) { val username = view?.recoverNameValue.orEmpty() val host = view?.recoverHostValue.orEmpty() - val symbol = view?.recoverSymbolValue.ifNullOrBlank { "Default" } + val symbol = view?.formHostSymbol.ifNullOrBlank { "Default" } with(disposable) { clear() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverView.kt index 693c52a3c..2e21d3351 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/recover/LoginRecoverView.kt @@ -6,9 +6,9 @@ interface LoginRecoverView : BaseView { val recoverHostValue: String - val recoverNameValue: String + val formHostSymbol: String - val recoverSymbolValue: String + val recoverNameValue: String val emailHintString: String @@ -22,18 +22,12 @@ interface LoginRecoverView : BaseView { fun clearUsernameError() - fun clearSymbolError() - - fun showSymbol(show: Boolean) - fun setErrorNameRequired() fun setUsernameHint(hint: String) fun setUsernameError(message: String) - fun setSymbolError(focus: Boolean) - fun showSoftKeyboard() fun hideSoftKeyboard() diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index 99a248024..ba261e095 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -202,7 +202,7 @@ android:layout_marginRight="24dp" android:hint="@string/login_host_hint" android:orientation="vertical" - app:layout_constraintBottom_toTopOf="@+id/loginFormSymbolLayout" + app:layout_constraintBottom_toTopOf="@+id/loginFormAdvancedButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginFormRecoverLink"> @@ -215,36 +215,6 @@ tools:ignore="Deprecated,LabelFor" />
- - - - - + app:layout_constraintTop_toBottomOf="@+id/loginFormHostLayout" /> @@ -105,7 +106,7 @@ android:layout_marginRight="24dp" android:hint="@string/login_host_hint" android:orientation="vertical" - app:layout_constraintBottom_toTopOf="@+id/loginRecoverSymbolLayout" + app:layout_constraintBottom_toTopOf="@+id/loginRecoverButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/loginRecoverNameLayout"> @@ -118,46 +119,17 @@ tools:ignore="Deprecated,LabelFor" /> - - - - -