From 4b6427794855937e131a690397d16afc28602563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 11 Oct 2022 23:23:11 +0200 Subject: [PATCH 01/53] [API/Usos] Add basic USOS API structure. --- .idea/dictionaries/Kuba.xml | 1 + .../edziennik/data/api/Errors.kt | 2 + .../edziennik/data/api/LoginMethods.kt | 10 ++ .../data/api/edziennik/usos/DataUsos.kt | 39 +++++++ .../edziennik/data/api/edziennik/usos/Usos.kt | 109 ++++++++++++++++++ .../data/api/edziennik/usos/UsosFeatures.kt | 18 +++ .../api/edziennik/usos/login/UsosLogin.kt | 54 +++++++++ .../api/edziennik/usos/login/UsosLoginApi.kt | 29 +++++ .../edziennik/ui/login/LoginInfo.kt | 19 ++- app/src/main/res/drawable/login_logo_usos.png | Bin 0 -> 15635 bytes app/src/main/res/values/errors.xml | 4 + app/src/main/res/values/strings.xml | 4 + 12 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt create mode 100644 app/src/main/res/drawable/login_logo_usos.png diff --git a/.idea/dictionaries/Kuba.xml b/.idea/dictionaries/Kuba.xml index 592a5d5e..aba38775 100644 --- a/.idea/dictionaries/Kuba.xml +++ b/.idea/dictionaries/Kuba.xml @@ -13,6 +13,7 @@ synergia szczodrzyński szkolny + usos \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 227561e6..617ef5ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -204,6 +204,8 @@ const val ERROR_PODLASIE_API_NO_TOKEN = 630 const val ERROR_PODLASIE_API_OTHER = 631 const val ERROR_PODLASIE_API_DATA_MISSING = 632 +const val ERROR_USOS_OAUTH_LOGIN_REQUEST = 701 + const val ERROR_TEMPLATE_WEB_OTHER = 801 const val EXCEPTION_API_TASK = 900 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt index 0f0c07ae..9825ea3f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.Mobidzie import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain import pl.szczodrzynski.edziennik.data.api.models.LoginMethod @@ -127,6 +128,15 @@ val podlasieLoginMethods = listOf( .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } ) +const val LOGIN_TYPE_USOS = 7 +const val LOGIN_MODE_USOS_OAUTH = 0 +const val LOGIN_METHOD_USOS_API = 100 +val usosLoginMethods = listOf( + LoginMethod(LOGIN_TYPE_USOS, LOGIN_METHOD_USOS_API, UsosLoginApi::class.java) + .withIsPossible { _, _ -> true } + .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } +) + val templateLoginMethods = listOf( LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java) .withIsPossible { _, _ -> true } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt new file mode 100644 index 00000000..b4a925bf --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-11. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos + +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API +import pl.szczodrzynski.edziennik.data.api.models.Data +import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.entity.Profile + +class DataUsos( + app: App, + profile: Profile?, + loginStore: LoginStore, +) : Data(app, profile, loginStore) { + + fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null + + override fun satisfyLoginMethods() { + loginMethods.clear() + if (isApiLoginValid()) { + loginMethods += LOGIN_METHOD_USOS_API + } + } + + override fun generateUserCode() = "USOS:TEST" + + var oauthTokenKey: String? + get() { mOauthTokenKey = mOauthTokenKey ?: loginStore.getLoginData("oauthTokenKey", null); return mOauthTokenKey } + set(value) { loginStore.putLoginData("oauthTokenKey", value); mOauthTokenKey = value } + private var mOauthTokenKey: String? = null + + var oauthTokenSecret: String? + get() { mOauthTokenSecret = mOauthTokenSecret ?: loginStore.getLoginData("oauthTokenSecret", null); return mOauthTokenSecret } + set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value } + private var mOauthTokenSecret: String? = null +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt new file mode 100644 index 00000000..c97e3695 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt @@ -0,0 +1,109 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-11. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos + +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin +import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback +import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.api.prepare +import pl.szczodrzynski.edziennik.data.api.usosLoginMethods +import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull +import pl.szczodrzynski.edziennik.data.db.full.EventFull +import pl.szczodrzynski.edziennik.data.db.full.MessageFull +import pl.szczodrzynski.edziennik.utils.Utils.d + +class Usos( + val app: App, + val profile: Profile?, + val loginStore: LoginStore, + val callback: EdziennikCallback, +) : EdziennikInterface { + companion object { + private const val TAG = "Usos" + } + + val internalErrorList = mutableListOf() + val data: DataUsos + + init { + data = DataUsos(app, profile, loginStore).apply { + callback = wrapCallback(this@Usos.callback) + satisfyLoginMethods() + } + } + + private fun completed() { + data.saveData() + callback.onCompleted() + } + + override fun sync( + featureIds: List, + viewId: Int?, + onlyEndpoints: List?, + arguments: JsonObject?, + ) { + data.arguments = arguments + data.prepare(usosLoginMethods, UsosFeatures, featureIds, viewId, onlyEndpoints) + d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}") + d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + UsosLogin(data) { + /*UsosData(data) { + completed() + }*/ + } + } + + override fun getMessage(message: MessageFull) {} + override fun sendMessage(recipients: List, subject: String, text: String) {} + override fun markAllAnnouncementsAsRead() {} + override fun getAnnouncement(announcement: AnnouncementFull) {} + override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {} + override fun getRecipientList() {} + override fun getEvent(eventFull: EventFull) {} + + override fun firstLogin() { + /*UsosFirstLogin(data) { + completed() + }*/ + } + + override fun cancel() { + d(TAG, "Cancelled") + data.cancel() + } + + private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { + return object : EdziennikCallback { + override fun onCompleted() { + callback.onCompleted() + } + + override fun onProgress(step: Float) { + callback.onProgress(step) + } + + override fun onStartProgress(stringRes: Int) { + callback.onStartProgress(stringRes) + } + + override fun onError(apiError: ApiError) { + when (apiError.errorCode) { + in internalErrorList -> { + // finish immediately if the same error occurs twice during the same sync + callback.onError(apiError) + } + else -> callback.onError(apiError) + } + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt new file mode 100644 index 00000000..a4ee1389 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-11. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos + +import pl.szczodrzynski.edziennik.data.api.FEATURE_STUDENT_INFO +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS +import pl.szczodrzynski.edziennik.data.api.models.Feature + +const val ENDPOINT_USOS_API_USER = 7000 + +val UsosFeatures = listOf( + Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf( + ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API, + ), listOf(LOGIN_METHOD_USOS_API)), +) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt new file mode 100644 index 00000000..599b8f16 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-11. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login + +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.utils.Utils.d + +class UsosLogin(val data: DataUsos, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "UsosLogin" + } + + private var cancelled = false + + init { + nextLoginMethod(onSuccess) + } + + private fun nextLoginMethod(onSuccess: () -> Unit) { + if (data.targetLoginMethodIds.isEmpty()) { + onSuccess() + return + } + if (cancelled) { + onSuccess() + return + } + useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + data.progress(data.progressStep) + if (usedMethodId != -1) + data.loginMethods.add(usedMethodId) + nextLoginMethod(onSuccess) + } + } + + private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + // this should never be true + if (data.loginMethods.contains(loginMethodId)) { + onSuccess(-1) + return + } + d(TAG, "Using login method $loginMethodId") + when (loginMethodId) { + LOGIN_METHOD_USOS_API -> { + data.startProgress(R.string.edziennik_progress_login_usos_api) + UsosLoginApi(data) { onSuccess(loginMethodId) } + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt new file mode 100644 index 00000000..bdf771c3 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-11. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login + +import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_MISSING +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.models.ApiError + +class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "UsosLoginApi" + } + + init { run { + if (data.profile == null) { + data.error(ApiError(TAG, ERROR_PROFILE_MISSING)) + return@run + } + + if (data.isApiLoginValid()) { + onSuccess() + } else { + data.error(ApiError(TAG, ERROR_USOS_OAUTH_LOGIN_REQUEST)) + } + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt index 0448b514..be6d62d8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt @@ -313,7 +313,24 @@ object LoginInfo { errorCodes = mapOf() ) ) - ) + ), + Register( + loginType = LOGIN_TYPE_USOS, + internalName = "usos", + registerName = R.string.login_type_usos, + registerLogo = R.drawable.login_logo_usos, + loginModes = listOf( + Mode( + loginMode = LOGIN_MODE_USOS_OAUTH, + name = R.string.login_mode_usos_oauth, + icon = R.drawable.login_logo_usos, + guideText = R.string.login_mode_usos_oauth_guide, + isPlatformSelection = true, + credentials = listOf(), + errorCodes = mapOf(), + ), + ), + ), ) } diff --git a/app/src/main/res/drawable/login_logo_usos.png b/app/src/main/res/drawable/login_logo_usos.png new file mode 100644 index 0000000000000000000000000000000000000000..7c376bddaf28d4462635115fed43a00a484a8a3c GIT binary patch literal 15635 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml index f0916a8b..4e978f7b 100644 --- a/app/src/main/res/values/errors.xml +++ b/app/src/main/res/values/errors.xml @@ -174,6 +174,8 @@ ERROR_PODLASIE_API_OTHER ERROR_PODLASIE_API_DATA_MISSING + ERROR_USOS_OAUTH_LOGIN_REQUEST + ERROR_TEMPLATE_WEB_OTHER EXCEPTION_API_TASK @@ -364,6 +366,8 @@ ERROR_PODLASIE_API_OTHER Brak danych. Zgłoś błąd programiście. + Wymagane logowanie w przeglądarce + ERROR_TEMPLATE_WEB_OTHER Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a8f81073..66ac0299 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1537,4 +1537,8 @@ (rodzic) - nieznany przedmiot - {cmd-information-outline} Oceny, których przedmiot nie został podany w dzienniku. Może to być na przykład taki, który nie jest prowadzony w tym roku szkolnym. + Logowanie do USOS API... + USOS + Logowanie z użyciem przeglądarki + TODO From 7935d0f097527614be4cdf42b641fc047e3b821d Mon Sep 17 00:00:00 2001 From: kuba2k2 Date: Thu, 13 Oct 2022 11:45:17 +0200 Subject: [PATCH 02/53] [API] Pass parameters to user action required errors. --- .../szczodrzynski/edziennik/MainActivity.kt | 5 +- .../api/events/UserActionRequiredEvent.kt | 5 +- .../edziennik/data/api/models/ApiError.kt | 7 +++ .../ui/login/LoginProgressFragment.kt | 5 +- .../utils/managers/UserActionManager.kt | 50 ++++++++++++++----- app/src/main/res/values/strings.xml | 1 + 6 files changed, 55 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 7197ea10..30c3a3e0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -853,7 +853,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { @Subscribe(threadMode = ThreadMode.MAIN) fun onUserActionRequiredEvent(event: UserActionRequiredEvent) { - app.userActionManager.execute(this, event.profileId, event.type) + app.userActionManager.execute(this, event.profileId, event.type, event.params) } private fun fragmentToSyncName(currentFragment: Int): Int { @@ -914,7 +914,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope { app.userActionManager.execute( this, extras.getInt("profileId"), - extras.getInt("type") + extras.getInt("type"), + extras.getBundle("params"), ) true } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt index 49b510c2..da68f3e8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt @@ -4,11 +4,14 @@ package pl.szczodrzynski.edziennik.data.api.events -data class UserActionRequiredEvent(val profileId: Int, val type: Int) { +import android.os.Bundle + +data class UserActionRequiredEvent(val profileId: Int, val type: Int, val params: Bundle?) { companion object { const val LOGIN_DATA_MOBIDZIENNIK = 101 const val LOGIN_DATA_LIBRUS = 102 const val LOGIN_DATA_VULCAN = 104 const val CAPTCHA_LIBRUS = 202 + const val OAUTH_USOS = 701 } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/ApiError.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/ApiError.kt index bb5d20cc..b631ed7d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/ApiError.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/ApiError.kt @@ -5,6 +5,7 @@ package pl.szczodrzynski.edziennik.data.api.models import android.content.Context +import android.os.Bundle import com.google.gson.JsonObject import im.wangchao.mhttp.Request import im.wangchao.mhttp.Response @@ -30,6 +31,7 @@ class ApiError(val tag: String, var errorCode: Int) { var request: Request? = null var response: Response? = null var isCritical = true + var params: Bundle? = null fun withThrowable(throwable: Throwable?): ApiError { this.throwable = throwable @@ -58,6 +60,11 @@ class ApiError(val tag: String, var errorCode: Int) { return this } + fun withParams(bundle: Bundle): ApiError { + this.params = bundle + return this + } + fun getStringText(context: Context): String { return context.resources.getIdentifier("error_${errorCode}", "string", context.packageName).let { if (it != 0) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt index 03abbc2b..ee29575e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt @@ -137,9 +137,8 @@ class LoginProgressFragment : Fragment(), CoroutineScope { return } - app.userActionManager.execute(activity, event.profileId, event.type, onSuccess = { code -> - args.putString("recaptchaCode", code) - args.putLong("recaptchaTime", System.currentTimeMillis()) + app.userActionManager.execute(activity, event.profileId, event.type, event.params, onSuccess = { params -> + args.putAll(params) doFirstLogin(args) }, onFailure = { activity.error(ApiError(TAG, ERROR_CAPTCHA_NEEDED)) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index dbe05325..76d5733d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.utils.managers import android.app.NotificationManager import android.app.PendingIntent import android.content.Context +import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationCompat import org.greenrobot.eventbus.EventBus @@ -14,9 +15,11 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.ERROR_CAPTCHA_LIBRUS_PORTAL +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.Intent import pl.szczodrzynski.edziennik.ext.JsonObject import pl.szczodrzynski.edziennik.ext.pendingIntentFlag @@ -27,18 +30,21 @@ class UserActionManager(val app: App) { private const val TAG = "UserActionManager" } - fun requiresUserAction(apiError: ApiError): Boolean { - return apiError.errorCode == ERROR_CAPTCHA_LIBRUS_PORTAL + fun requiresUserAction(apiError: ApiError) = when (apiError.errorCode) { + ERROR_CAPTCHA_LIBRUS_PORTAL -> true + ERROR_USOS_OAUTH_LOGIN_REQUEST -> true + else -> false } fun sendToUser(apiError: ApiError) { val type = when (apiError.errorCode) { ERROR_CAPTCHA_LIBRUS_PORTAL -> UserActionRequiredEvent.CAPTCHA_LIBRUS + ERROR_USOS_OAUTH_LOGIN_REQUEST -> UserActionRequiredEvent.OAUTH_USOS else -> 0 } if (EventBus.getDefault().hasSubscriberForEvent(UserActionRequiredEvent::class.java)) { - EventBus.getDefault().post(UserActionRequiredEvent(apiError.profileId ?: -1, type)) + EventBus.getDefault().post(UserActionRequiredEvent(apiError.profileId ?: -1, type, apiError.params)) return } @@ -46,6 +52,7 @@ class UserActionManager(val app: App) { val text = app.getString(when (type) { UserActionRequiredEvent.CAPTCHA_LIBRUS -> R.string.notification_user_action_required_captcha_librus + UserActionRequiredEvent.OAUTH_USOS -> R.string.notification_user_action_required_oauth_usos else -> R.string.notification_user_action_required_text }, apiError.profileId) @@ -54,7 +61,8 @@ class UserActionManager(val app: App) { MainActivity::class.java, "action" to "userActionRequired", "profileId" to (apiError.profileId ?: -1), - "type" to type + "type" to type, + "params" to apiError.params, ) val pendingIntent = PendingIntent.getActivity(app, System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag()) @@ -78,23 +86,41 @@ class UserActionManager(val app: App) { activity: AppCompatActivity, profileId: Int?, type: Int, - onSuccess: ((code: String) -> Unit)? = null, + params: Bundle? = null, + onSuccess: ((params: Bundle) -> Unit)? = null, onFailure: (() -> Unit)? = null ) { - if (type != UserActionRequiredEvent.CAPTCHA_LIBRUS) - return + when (type) { + UserActionRequiredEvent.CAPTCHA_LIBRUS -> executeLibrus(activity, profileId, onSuccess, onFailure) + UserActionRequiredEvent.OAUTH_USOS -> executeOauth(activity, profileId, params, onSuccess, onFailure) + } + } + private fun executeLibrus( + activity: AppCompatActivity, + profileId: Int?, + onSuccess: ((params: Bundle) -> Unit)? = null, + onFailure: (() -> Unit)? = null, + ) { if (profileId == null) return // show captcha dialog // use passed onSuccess listener, else sync profile LibrusCaptchaDialog( activity = activity, - onSuccess = onSuccess ?: { code -> - EdziennikTask.syncProfile(profileId, arguments = JsonObject( - "recaptchaCode" to code, - "recaptchaTime" to System.currentTimeMillis() - )).enqueue(activity) + onSuccess = { code -> + if (onSuccess != null) { + val params = Bundle( + "recaptchaCode" to code, + "recaptchaTime" to System.currentTimeMillis(), + ) + onSuccess(params) + } else { + EdziennikTask.syncProfile(profileId, arguments = JsonObject( + "recaptchaCode" to code, + "recaptchaTime" to System.currentTimeMillis(), + )).enqueue(activity) + } }, onFailure = onFailure ).show() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 66ac0299..393248c9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1541,4 +1541,5 @@ USOS Logowanie z użyciem przeglądarki TODO + USOS - wymagane logowanie z użyciem przeglądarki From c7362bce12e5615d36eef04df93ed384491a339f Mon Sep 17 00:00:00 2001 From: kuba2k2 Date: Thu, 13 Oct 2022 21:27:55 +0200 Subject: [PATCH 03/53] [API/Usos] Add base rest API class. --- .../data/api/edziennik/usos/DataUsos.kt | 25 +++ .../data/api/edziennik/usos/data/UsosApi.kt | 170 ++++++++++++++++++ .../data/api/edziennik/usos/data/UsosData.kt | 49 +++++ .../edziennik/ext/TextExtensions.kt | 8 + .../utils/managers/UserActionManager.kt | 16 +- 5 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt index b4a925bf..1dee14ba 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -27,6 +27,21 @@ class DataUsos( override fun generateUserCode() = "USOS:TEST" + var instanceUrl: String? + get() { mInstanceUrl = mInstanceUrl ?: loginStore.getLoginData("instanceUrl", null); return mInstanceUrl } + set(value) { loginStore.putLoginData("instanceUrl", value); mInstanceUrl = value } + private var mInstanceUrl: String? = null + + var oauthConsumerKey: String? + get() { mOauthConsumerKey = mOauthConsumerKey ?: loginStore.getLoginData("oauthConsumerKey", null); return mOauthConsumerKey } + set(value) { loginStore.putLoginData("oauthConsumerKey", value); mOauthConsumerKey = value } + private var mOauthConsumerKey: String? = null + + var oauthConsumerSecret: String? + get() { mOauthConsumerSecret = mOauthConsumerSecret ?: loginStore.getLoginData("oauthConsumerSecret", null); return mOauthConsumerSecret } + set(value) { loginStore.putLoginData("oauthConsumerSecret", value); mOauthConsumerSecret = value } + private var mOauthConsumerSecret: String? = null + var oauthTokenKey: String? get() { mOauthTokenKey = mOauthTokenKey ?: loginStore.getLoginData("oauthTokenKey", null); return mOauthTokenKey } set(value) { loginStore.putLoginData("oauthTokenKey", value); mOauthTokenKey = value } @@ -36,4 +51,14 @@ class DataUsos( get() { mOauthTokenSecret = mOauthTokenSecret ?: loginStore.getLoginData("oauthTokenSecret", null); return mOauthTokenSecret } set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value } private var mOauthTokenSecret: String? = null + + var studentId: String? + get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId } + set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } + private var mStudentId: String? = null + + var studentNumber: String? + get() { mStudentNumber = mStudentNumber ?: profile?.getStudentData("studentNumber", null); return mStudentNumber } + set(value) { profile?.putStudentData("studentNumber", value) ?: return; mStudentNumber = value } + private var mStudentNumber: String? = null } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt new file mode 100644 index 00000000..6ffcd46a --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -0,0 +1,170 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-13. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import im.wangchao.mhttp.AbsCallbackHandler +import im.wangchao.mhttp.Request +import im.wangchao.mhttp.Response +import im.wangchao.mhttp.body.MediaTypeUtils +import im.wangchao.mhttp.callback.JsonArrayCallbackHandler +import im.wangchao.mhttp.callback.JsonCallbackHandler +import im.wangchao.mhttp.callback.TextCallbackHandler +import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE +import pl.szczodrzynski.edziennik.data.api.SERVER_USER_AGENT +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.ext.currentTimeUnix +import pl.szczodrzynski.edziennik.ext.hmacSHA1 +import pl.szczodrzynski.edziennik.ext.toQueryString +import pl.szczodrzynski.edziennik.ext.urlEncode +import pl.szczodrzynski.edziennik.utils.Utils.d +import java.net.HttpURLConnection.* +import java.util.UUID + +open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { + companion object { + private const val TAG = "UsosApi" + } + + enum class ResponseType { + OBJECT, + ARRAY, + PLAIN, + } + + val profileId + get() = data.profile?.id ?: -1 + + val profile + get() = data.profile + + private fun valueToString(value: Any) = when (value) { + is String -> value + is Number -> value.toString() + is List<*> -> listToString(value) + else -> value.toString() + } + + private fun listToString(list: List<*>): String { + return list.map { + if (it is Pair<*, *> && it.first is String && it.second is List<*>) + return@map "${it.first}[${listToString(it.second as List<*>)}]" + return@map valueToString(it ?: "") + }.joinToString("|") + } + + private fun buildSignature(method: String, url: String, params: Map): String { + val query = params.toQueryString() + val signatureString = listOf( + method.uppercase(), + url.urlEncode(), + query.urlEncode(), + ).joinToString("&") + val signingKey = listOf( + data.oauthConsumerSecret ?: "", + data.oauthTokenSecret ?: "", + ).joinToString("&") { it.urlEncode() } + return signatureString.hmacSHA1(signingKey) + } + + fun apiRequest( + tag: String, + service: String, + params: Map, + responseType: ResponseType, + onSuccess: (data: T) -> Unit, + ) { + val url = "${data.instanceUrl}/services/$service" + d(tag, "Request: Usos/Api - $url") + val formData = params.mapValues { + valueToString(it.value) + } + val auth = mutableMapOf( + "realm" to url, + "oauth_consumer_key" to (data.oauthConsumerKey ?: ""), + "oauth_nonce" to UUID.randomUUID().toString(), + "oauth_signature_method" to "HMAC-SHA1", + "oauth_timestamp" to currentTimeUnix().toString(), + "oauth_token" to (data.oauthTokenKey ?: ""), + "oauth_version" to "1.0", + ) + val signature = buildSignature("POST", url, formData + auth) + auth["oauth_signature"] = signature + + val authString = auth.map { + """${it.key}="${it.value.urlEncode()}"""" + }.joinToString(", ") + + Request.builder() + .url(url) + .userAgent(SERVER_USER_AGENT) + .addHeader("Authorization", "OAuth $authString") + .post() + .setTextBody(formData.toQueryString(), MediaTypeUtils.APPLICATION_FORM) + .allowErrorCode(HTTP_BAD_REQUEST) + .allowErrorCode(HTTP_UNAUTHORIZED) + .allowErrorCode(HTTP_FORBIDDEN) + .allowErrorCode(HTTP_NOT_FOUND) + .allowErrorCode(HTTP_UNAVAILABLE) + .callback(getCallback(tag, responseType, onSuccess)) + .build() + .enqueue() + } + + @Suppress("UNCHECKED_CAST") + private fun getCallback( + tag: String, + responseType: ResponseType, + onSuccess: (data: T) -> Unit, + ) = when (responseType) { + ResponseType.OBJECT -> object : JsonCallbackHandler() { + override fun onSuccess(data: JsonObject?, response: Response?) { + processResponse(response, data as T, onSuccess) + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + processError(tag, response, throwable) + } + } + ResponseType.ARRAY -> object : JsonArrayCallbackHandler() { + override fun onSuccess(data: JsonArray?, response: Response?) { + processResponse(response, data as T, onSuccess) + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + processError(tag, response, throwable) + } + } + ResponseType.PLAIN -> object : TextCallbackHandler() { + override fun onSuccess(data: String?, response: Response?) { + processResponse(response, data as T, onSuccess) + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + processError(tag, response, throwable) + } + } + } + + private fun processResponse( + response: Response?, + data: T?, + onSuccess: (data: T) -> Unit, + ) { + + } + + private fun processError( + tag: String, + response: Response?, + throwable: Throwable?, + ) { + data.error(ApiError(tag, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable)) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt new file mode 100644 index 00000000..bea52ea3 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-13. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data + +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web.TemplateWebSample +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_USER +import pl.szczodrzynski.edziennik.utils.Utils.d + +class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "UsosData" + } + + init { + nextEndpoint(onSuccess) + } + + private fun nextEndpoint(onSuccess: () -> Unit) { + if (data.targetEndpointIds.isEmpty()) { + onSuccess() + return + } + if (data.cancelled) { + onSuccess() + return + } + val id = data.targetEndpointIds.firstKey() + val lastSync = data.targetEndpointIds.remove(id) + useEndpoint(id, lastSync) { endpointId -> + data.progress(data.progressStep) + nextEndpoint(onSuccess) + } + } + + private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) { + d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync") + when (endpointId) { + ENDPOINT_USOS_API_USER -> { + data.startProgress(R.string.edziennik_progress_endpoint_student_info) + TemplateWebSample(data, lastSync, onSuccess) + } + else -> onSuccess(endpointId) + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt index ebfb1410..84fe6631 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt @@ -18,6 +18,7 @@ import android.text.style.StyleSpan import androidx.annotation.PluralsRes import androidx.annotation.StringRes import com.mikepenz.materialdrawer.holder.StringHolder +import java.net.URLEncoder fun CharSequence?.isNotNullNorEmpty(): Boolean { return this != null && this.isNotEmpty() @@ -343,3 +344,10 @@ fun Int.toStringHolder() = StringHolder(this) fun CharSequence.toStringHolder() = StringHolder(this) fun @receiver:StringRes Int.resolveString(context: Context) = context.getString(this) + +fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8").replace("+", "%20") + +fun Map.toQueryString() = this + .map { it.key.urlEncode() to it.value.urlEncode() } + .sortedBy { it.first } + .joinToString("&") { "${it.first}=${it.second}" } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index 76d5733d..537915ac 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -99,8 +99,8 @@ class UserActionManager(val app: App) { private fun executeLibrus( activity: AppCompatActivity, profileId: Int?, - onSuccess: ((params: Bundle) -> Unit)? = null, - onFailure: (() -> Unit)? = null, + onSuccess: ((params: Bundle) -> Unit)?, + onFailure: (() -> Unit)?, ) { if (profileId == null) return @@ -125,4 +125,16 @@ class UserActionManager(val app: App) { onFailure = onFailure ).show() } + + private fun executeOauth( + activity: AppCompatActivity, + profileId: Int?, + params: Bundle?, + onSuccess: ((params: Bundle) -> Unit)?, + onFailure: (() -> Unit)?, + ) { + if (profileId == null || params == null) + return + + } } From c983c16907312a75d058abab251d34b86e9f24d2 Mon Sep 17 00:00:00 2001 From: Adam Kasprzycki <66315787+santoni0@users.noreply.github.com> Date: Fri, 14 Oct 2022 00:24:00 +0200 Subject: [PATCH 04/53] [UI] Request notifications permission on API >= 33. (#143) * Added requesting notifications permission on Android 13 devices * Move permission check to PermissionManager * Request permission on home screen --- app/src/main/AndroidManifest.xml | 2 +- .../edziennik/ui/home/HomeFragment.kt | 7 +++++- .../ui/login/LoginChooserFragment.kt | 10 +++++--- .../utils/managers/PermissionManager.kt | 24 ++++++++++++++++++- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c5c273b4..4119bf65 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ - + diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt index 54f94433..635c7b56 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt @@ -81,7 +81,8 @@ class HomeFragment : Fragment(), CoroutineScope { private val job: Job = Job() override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main - + private val manager + get() = app.permissionManager override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { activity = (getActivity() as MainActivity?) ?: return null context ?: return null @@ -96,6 +97,10 @@ class HomeFragment : Fragment(), CoroutineScope { if (!isAdded) return + if (!manager.isNotificationPermissionGranted) { + manager.requestNotificationsPermission(activity, 0, false){} + } + activity.bottomSheet.prependItems( BottomSheetPrimaryItem(true) .withTitle(R.string.menu_add_remove_cards) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt index 1bfe0abd..a4367dee 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt @@ -23,8 +23,8 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.* -import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog @@ -51,7 +51,8 @@ class LoginChooserFragment : Fragment(), CoroutineScope { private val job: Job = Job() override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main - + private val manager + get() = app.permissionManager // local/private variables go here override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -67,6 +68,9 @@ class LoginChooserFragment : Fragment(), CoroutineScope { if (!isAdded) return val adapter = LoginChooserAdapter(activity, this::onLoginModeClicked) + if (!manager.isNotificationPermissionGranted) { + manager.requestNotificationsPermission(activity, 0, false){} + } b.versionText.setText( R.string.login_chooser_version_format, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt index 65430f60..e99f9e3e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/PermissionManager.kt @@ -36,7 +36,13 @@ class PermissionManager(val app: App) : CoroutineScope { app.checkSelfPermission(name) == PackageManager.PERMISSION_GRANTED else true - + val isNotificationPermissionGranted by lazy { + if (Build.VERSION.SDK_INT >= 33) { + app.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED + } else { + true + } + } private fun openPermissionSettings(activity: AppCompatActivity) { val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val uri = Uri.fromParts("package", app.packageName, null) @@ -80,6 +86,10 @@ class PermissionManager(val app: App) : CoroutineScope { .show() } result.hasPermanentDenied() -> { + if (!isRequired) { + onSuccess() + return@launch + } MaterialAlertDialogBuilder(activity) .setTitle(R.string.permissions_required) .setMessage(R.string.permissions_denied) @@ -92,6 +102,18 @@ class PermissionManager(val app: App) : CoroutineScope { } } } + fun requestNotificationsPermission( + activity: AppCompatActivity, + @StringRes permissionMessage: Int, + isRequired: Boolean = false, + onSuccess: suspend CoroutineScope.() -> Unit + ) = requestPermission( + activity, + permissionMessage, + isRequired, + Manifest.permission.POST_NOTIFICATIONS, + onSuccess + ) fun requestStoragePermission( activity: AppCompatActivity, From 55369eaa8b110185e40e27911bd3b90ba39b2375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 14 Oct 2022 00:25:22 +0200 Subject: [PATCH 05/53] [UI/Timetable] Add Timetable settings. (#140) * [UI/Timetable] Add timetable config dialog and implement UI options. * [UI/Timetable] Fix reloading timetable after changing config. * [UI/Timetable] Fix calculating lesson range boundaries. --- .../edziennik/config/ProfileConfigUI.kt | 15 +++++ .../dialogs/settings/TimetableConfigDialog.kt | 44 +++++++++++++++ .../ui/timetable/TimetableDayFragment.kt | 56 ++++++++++++------- .../ui/timetable/TimetableFragment.kt | 13 ++++- .../edziennik/utils/MutableLazy.kt | 7 ++- .../main/res/layout/dialog_config_agenda.xml | 2 +- .../res/layout/timetable_config_dialog.xml | 56 +++++++++++++++++++ app/src/main/res/values-en/strings.xml | 2 +- app/src/main/res/values/strings.xml | 6 +- 9 files changed, 173 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt create mode 100644 app/src/main/res/layout/timetable_config_dialog.xml diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt index 187cb6bd..743872b0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt @@ -69,4 +69,19 @@ class ProfileConfigUI(private val config: ProfileConfig) { var messagesGreetingText: String? get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText } set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value } + + private var mTimetableShowAttendance: Boolean? = null + var timetableShowAttendance: Boolean + get() { mTimetableShowAttendance = mTimetableShowAttendance ?: config.values.get("timetableShowAttendance", true); return mTimetableShowAttendance ?: true } + set(value) { config.set("timetableShowAttendance", value); mTimetableShowAttendance = value } + + private var mTimetableShowEvents: Boolean? = null + var timetableShowEvents: Boolean + get() { mTimetableShowEvents = mTimetableShowEvents ?: config.values.get("timetableShowEvents", true); return mTimetableShowEvents ?: true } + set(value) { config.set("timetableShowEvents", value); mTimetableShowEvents = value } + + private var mTimetableTrimHourRange: Boolean? = null + var timetableTrimHourRange: Boolean + get() { mTimetableTrimHourRange = mTimetableTrimHourRange ?: config.values.get("timetableTrimHourRange", false); return mTimetableTrimHourRange ?: false } + set(value) { config.set("timetableTrimHourRange", value); mTimetableTrimHourRange = value } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt new file mode 100644 index 00000000..b784165b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-7. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs.settings + +import android.view.LayoutInflater +import androidx.appcompat.app.AppCompatActivity +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.databinding.TimetableConfigDialogBinding +import pl.szczodrzynski.edziennik.ext.Intent +import pl.szczodrzynski.edziennik.ext.onClick +import pl.szczodrzynski.edziennik.ui.dialogs.base.ConfigDialog +import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment + +class TimetableConfigDialog( + activity: AppCompatActivity, + reloadOnDismiss: Boolean = true, + onShowListener: ((tag: String) -> Unit)? = null, + onDismissListener: ((tag: String) -> Unit)? = null, +) : ConfigDialog( + activity, + reloadOnDismiss, + onShowListener, + onDismissListener, +) { + + override val TAG = "TimetableConfigDialog" + + override fun getTitleRes() = R.string.menu_timetable_config + override fun inflate(layoutInflater: LayoutInflater) = + TimetableConfigDialogBinding.inflate(layoutInflater) + + private val profileConfig by lazy { app.config.getFor(app.profileId).ui } + + override suspend fun loadConfig() { + b.config = profileConfig + } + + override suspend fun saveConfig() { + activity.sendBroadcast(Intent(TimetableFragment.ACTION_RELOAD_PAGES)) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt index 754bd4f5..a2d99247 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt @@ -36,6 +36,7 @@ import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAU import pl.szczodrzynski.edziennik.utils.managers.NoteManager import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time +import pl.szczodrzynski.edziennik.utils.mutableLazy import java.util.* import kotlin.coroutines.CoroutineContext import kotlin.math.min @@ -71,8 +72,9 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { // find SwipeRefreshLayout in the hierarchy private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) } + private val profileConfig by lazy { app.config.forProfile().ui } - private val dayView by lazy { + private val dayViewDelegate = mutableLazy { val dayView = DayView(activity, DayViewConfig( startHour = startHour, endHour = endHour, @@ -85,8 +87,9 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { eventMargin = 2.dp ), true) dayView.setPadding(10.dp) - return@lazy dayView + return@mutableLazy dayView } + private val dayView by dayViewDelegate override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { activity = (getActivity() as MainActivity?) ?: return null @@ -173,8 +176,19 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { return } + if (dayViewDelegate.isInitialized()) + b.dayFrame.removeView(dayView) + + val lessonsActual = lessons.filter { it.type != Lesson.TYPE_NO_LESSONS } + + if (profileConfig.timetableTrimHourRange) { + dayViewDelegate.deinitialize() + // end/start defaults are swapped on purpose + startHour = lessonsActual.minOf { it.displayStartTime?.hour ?: DEFAULT_END_HOUR } + endHour = lessonsActual.maxOf { it.displayEndTime?.hour?.plus(1) ?: DEFAULT_START_HOUR } + } + b.scrollView.isVisible = true - b.dayFrame.removeView(dayView) b.dayFrame.addView(dayView, 0) // Inflate a label view for each hour the day view will display @@ -195,7 +209,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { lessons.forEach { it.showAsUnseen = !it.seen } - buildLessonViews(lessons.filter { it.type != Lesson.TYPE_NO_LESSONS }, events, attendanceList) + buildLessonViews(lessonsActual, events, attendanceList) } private fun buildLessonViews(lessons: List, events: List, attendanceList: List) { @@ -215,7 +229,10 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) for (lesson in lessons) { - val attendance = attendanceList.find { it.startTime == lesson.startTime } + val attendance = if (profileConfig.timetableShowAttendance) + attendanceList.find { it.startTime == lesson.startTime } + else + null val startTime = lesson.displayStartTime ?: continue val endTime = lesson.displayEndTime ?: continue @@ -245,23 +262,20 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { } } - val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3) - eventList.getOrNull(0).let { - lb.event1.visibility = if (it == null) View.GONE else View.VISIBLE - lb.event1.background = it?.let { - R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor) + val eventIcons = listOf(lb.event1, lb.event2, lb.event3) + if (profileConfig.timetableShowEvents) { + val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3) + for ((i, eventIcon) in eventIcons.withIndex()) { + eventList.getOrNull(i).let { + eventIcon.isVisible = it != null + eventIcon.background = it?.let { + R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor) + } + } } - } - eventList.getOrNull(1).let { - lb.event2.visibility = if (it == null) View.GONE else View.VISIBLE - lb.event2.background = it?.let { - R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor) - } - } - eventList.getOrNull(2).let { - lb.event3.visibility = if (it == null) View.GONE else View.VISIBLE - lb.event3.background = it?.let { - R.drawable.bg_circle.resolveDrawable(activity).setTintColor(it.eventColor) + } else { + for (eventIcon in eventIcons) { + eventIcon.visibility = View.GONE } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt index b046ff68..fc2221bc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt @@ -26,6 +26,7 @@ import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains +import pl.szczodrzynski.edziennik.ui.dialogs.settings.TimetableConfigDialog import pl.szczodrzynski.edziennik.ui.event.EventManualDialog import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem @@ -52,6 +53,7 @@ class TimetableFragment : Fragment(), CoroutineScope { private var fabShown = false private val items = mutableListOf() + private val profileConfig by lazy { app.config.forProfile().ui } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { activity = (getActivity() as MainActivity?) ?: return null @@ -128,8 +130,8 @@ class TimetableFragment : Fragment(), CoroutineScope { } val lessonRanges = app.db.lessonRangeDao().getAllNow(App.profileId) - startHour = lessonRanges.map { it.startTime.hour }.minOrNull() ?: DEFAULT_START_HOUR - endHour = lessonRanges.map { it.endTime.hour }.maxOrNull()?.plus(1) ?: DEFAULT_END_HOUR + startHour = lessonRanges.minOfOrNull { it.startTime.hour } ?: DEFAULT_START_HOUR + endHour = lessonRanges.maxOfOrNull { it.endTime.hour }?.plus(1) ?: DEFAULT_END_HOUR } deferred.await() if (!isAdded) @@ -208,6 +210,13 @@ class TimetableFragment : Fragment(), CoroutineScope { activity.bottomSheet.close() GenerateBlockTimetableDialog(activity) }), + BottomSheetPrimaryItem(true) + .withTitle(R.string.menu_timetable_config) + .withIcon(CommunityMaterial.Icon.cmd_cog_outline) + .withOnClickListener { + activity.bottomSheet.close() + TimetableConfigDialog(activity, false, null, null).show() + }, BottomSheetSeparatorItem(true), BottomSheetPrimaryItem(true) .withTitle(R.string.menu_mark_as_read) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/MutableLazy.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/MutableLazy.kt index cf000e1f..f742c185 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/MutableLazy.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/MutableLazy.kt @@ -19,7 +19,6 @@ class MutableLazyImpl(initializer: () -> T, lock: Any? = null) { return synchronized(lock) { val typedValue = initializer!!() _value = typedValue - initializer = null typedValue } } @@ -29,7 +28,11 @@ class MutableLazyImpl(initializer: () -> T, lock: Any? = null) { fun isInitialized() = _value !== UNINITIALIZED_VALUE + fun deinitialize() { + _value = UNINITIALIZED_VALUE + } + override fun toString() = if (isInitialized()) _value.toString() else "ChangeableLazy value not initialized yet." } -fun mutableLazy(initializer: () -> T): MutableLazyImpl = MutableLazyImpl(initializer) \ No newline at end of file +fun mutableLazy(initializer: () -> T): MutableLazyImpl = MutableLazyImpl(initializer) diff --git a/app/src/main/res/layout/dialog_config_agenda.xml b/app/src/main/res/layout/dialog_config_agenda.xml index f17b5989..b51464e2 100644 --- a/app/src/main/res/layout/dialog_config_agenda.xml +++ b/app/src/main/res/layout/dialog_config_agenda.xml @@ -31,7 +31,7 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 851129f9..5dad0cb3 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -1383,7 +1383,7 @@ Grade read the Privacy Policy and accept its provisions.

The authors of the application are not responsible for the use of the Szkolny.eu application.]]>
Szkolny.eu v%s\n%s - Appearance + Appearance Online learning online lesson Messages settings diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a8f81073..3cf6221c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1424,7 +1424,7 @@ przeczytanie Polityki prywatności i akceptujesz jej postanowienia.

Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]>
Szkolny.eu v%s\n%s Ustawienia terminarza - Wygląd + Wygląd Pokazuj zmiany planu lekcji Pokazuj nieobecności nauczycieli Tryb kompaktowy @@ -1537,4 +1537,8 @@ (rodzic) - nieznany przedmiot - {cmd-information-outline} Oceny, których przedmiot nie został podany w dzienniku. Może to być na przykład taki, który nie jest prowadzony w tym roku szkolnym. + Ustawienia planu lekcji + Pokazuj wydarzenia przy lekcjach + Pokazuj rodzaj obecności na lekcji + Nie pokazuj godzin bez lekcji From 9f3aaf6e8685f40731fa1a4a6200ea6ca648ffb4 Mon Sep 17 00:00:00 2001 From: kuba2k2 Date: Fri, 14 Oct 2022 14:43:40 +0200 Subject: [PATCH 06/53] [API] Move register platforms to new endpoint. --- .../edziennik/data/api/szkolny/SzkolnyApi.kt | 4 ++-- .../edziennik/data/api/szkolny/SzkolnyService.kt | 4 ++-- .../edziennik/ui/login/LoginFormFragment.kt | 12 ++++++++---- .../pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt | 4 +++- .../edziennik/ui/login/LoginPlatformListFragment.kt | 3 ++- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt index c86ae235..a9f6a69f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt @@ -451,9 +451,9 @@ class SzkolnyApi(val app: App) : CoroutineScope { @Throws(Exception::class) fun getRealms(registerName: String): List { - val response = api.fsLoginRealms(registerName).execute() + val response = api.platforms(registerName).execute() if (response.isSuccessful && response.body() != null) { - return response.body()!! + return parseResponse(response) } throw SzkolnyApiException(null) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt index 5c60c3ff..cca9475a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyService.kt @@ -45,6 +45,6 @@ interface SzkolnyService { @GET("registerAvailability") fun registerAvailability(): Call>> - @GET("https://szkolny-eu.github.io/FSLogin/realms/{registerName}.json") - fun fsLoginRealms(@Path("registerName") registerName: String): Call> + @GET("platforms/{registerName}") + fun platforms(@Path("registerName") registerName: String): Call>> } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt index 3c5a26ca..5586dd77 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt @@ -33,7 +33,6 @@ import pl.szczodrzynski.edziennik.ui.login.LoginInfo.BaseCredential import pl.szczodrzynski.edziennik.ui.login.LoginInfo.FormCheckbox import pl.szczodrzynski.edziennik.ui.login.LoginInfo.FormField import pl.szczodrzynski.navlib.colorAttr -import java.util.* import kotlin.coroutines.CoroutineContext class LoginFormFragment : Fragment(), CoroutineScope { @@ -63,8 +62,10 @@ class LoginFormFragment : Fragment(), CoroutineScope { get() = arguments?.getString("platformDescription") private val platformFormFields get() = arguments?.getString("platformFormFields")?.split(";") - private val platformRealmData - get() = arguments?.getString("platformRealmData")?.toJsonObject() + private val platformData + get() = arguments?.getString("platformData")?.toJsonObject() + private val platformStoreKey + get() = arguments?.getString("platformStoreKey") override fun onCreateView( inflater: LayoutInflater, @@ -250,7 +251,10 @@ class LoginFormFragment : Fragment(), CoroutineScope { payload.putBoolean("fakeLogin", true) } - payload.putBundle("webRealmData", platformRealmData?.toBundle()) + if (platformStoreKey == null) + payload.putAll(platformData?.toBundle()) + else + payload.putBundle(platformStoreKey, platformData?.toBundle()) var hasErrors = false credentials.forEach { (credential, b) -> diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt index be6d62d8..15a7021d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt @@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.ui.login import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import com.google.gson.JsonObject import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import pl.szczodrzynski.edziennik.R @@ -374,7 +375,8 @@ object LoginInfo { val icon: String, val screenshot: String?, val formFields: List, - val realmData: RealmData + val data: JsonObject, + val storeKey: String?, ) open class BaseCredential( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt index 8a2bb25d..cff801a4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt @@ -68,7 +68,8 @@ class LoginPlatformListFragment : Fragment(), CoroutineScope { "platformName" to platform.name, "platformDescription" to platform.description, "platformFormFields" to platform.formFields.joinToString(";"), - "platformRealmData" to app.gson.toJson(platform.realmData) + "platformData" to platform.data, + "platformStoreKey" to platform.storeKey, ), activity.navOptions) } From 6c96875c8332b8902d7ecf19038a58ce1cd465c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 14 Oct 2022 19:44:22 +0200 Subject: [PATCH 07/53] [API/Login] Allow passing LoginStore params in user action requests. --- .../edziennik/ui/login/LoginFormFragment.kt | 7 ++++- .../ui/login/LoginPlatformListFragment.kt | 2 +- .../utils/managers/UserActionManager.kt | 30 ++++++++++--------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt index 5586dd77..b403568b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt @@ -91,6 +91,11 @@ class LoginFormFragment : Fragment(), CoroutineScope { val loginMode = arguments?.getInt("loginMode") ?: return val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return + if (mode.credentials.isEmpty()) { + login(loginType, loginMode) + return + } + b.title.setText(R.string.login_form_title_format, app.getString(register.registerName)) b.subTitle.text = platformName ?: app.getString(mode.name) b.text.text = platformGuideText ?: app.getString(mode.guideText) @@ -252,7 +257,7 @@ class LoginFormFragment : Fragment(), CoroutineScope { } if (platformStoreKey == null) - payload.putAll(platformData?.toBundle()) + payload.putAll(platformData?.toBundle() ?: Bundle()) else payload.putBundle(platformStoreKey, platformData?.toBundle()) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt index cff801a4..5629487f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt @@ -68,7 +68,7 @@ class LoginPlatformListFragment : Fragment(), CoroutineScope { "platformName" to platform.name, "platformDescription" to platform.description, "platformFormFields" to platform.formFields.joinToString(";"), - "platformData" to platform.data, + "platformData" to platform.data.toString(), "platformStoreKey" to platform.storeKey, ), activity.navOptions) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index 537915ac..bbdb8602 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -19,11 +19,9 @@ import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError -import pl.szczodrzynski.edziennik.ext.Bundle -import pl.szczodrzynski.edziennik.ext.Intent -import pl.szczodrzynski.edziennik.ext.JsonObject -import pl.szczodrzynski.edziennik.ext.pendingIntentFlag +import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog +import pl.szczodrzynski.edziennik.utils.Utils.d class UserActionManager(val app: App) { companion object { @@ -90,8 +88,9 @@ class UserActionManager(val app: App) { onSuccess: ((params: Bundle) -> Unit)? = null, onFailure: (() -> Unit)? = null ) { + d(TAG, "Running user action ($type) with params: ${params?.toJsonObject()}") when (type) { - UserActionRequiredEvent.CAPTCHA_LIBRUS -> executeLibrus(activity, profileId, onSuccess, onFailure) + UserActionRequiredEvent.CAPTCHA_LIBRUS -> executeLibrus(activity, profileId, params, onSuccess, onFailure) UserActionRequiredEvent.OAUTH_USOS -> executeOauth(activity, profileId, params, onSuccess, onFailure) } } @@ -99,27 +98,29 @@ class UserActionManager(val app: App) { private fun executeLibrus( activity: AppCompatActivity, profileId: Int?, + params: Bundle?, onSuccess: ((params: Bundle) -> Unit)?, onFailure: (() -> Unit)?, ) { if (profileId == null) return + val extras = params?.getBundle("extras") // show captcha dialog // use passed onSuccess listener, else sync profile LibrusCaptchaDialog( activity = activity, onSuccess = { code -> + val args = Bundle( + "recaptchaCode" to code, + "recaptchaTime" to System.currentTimeMillis(), + ) + if (extras != null) + args.putAll(extras) + if (onSuccess != null) { - val params = Bundle( - "recaptchaCode" to code, - "recaptchaTime" to System.currentTimeMillis(), - ) - onSuccess(params) + onSuccess(args) } else { - EdziennikTask.syncProfile(profileId, arguments = JsonObject( - "recaptchaCode" to code, - "recaptchaTime" to System.currentTimeMillis(), - )).enqueue(activity) + EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) } }, onFailure = onFailure @@ -135,6 +136,7 @@ class UserActionManager(val app: App) { ) { if (profileId == null || params == null) return + val extras = params.getBundle("extras") } } From 2ff784066efc716c82b2843293eb6ecbe9ac86b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 14 Oct 2022 21:44:58 +0200 Subject: [PATCH 08/53] [API/Usos] Implement OAuth authorization flow. --- .../edziennik/data/api/Constants.kt | 9 +++ .../data/api/edziennik/EdziennikTask.kt | 2 + .../data/api/edziennik/usos/DataUsos.kt | 10 +++ .../edziennik/data/api/edziennik/usos/Usos.kt | 5 +- .../data/api/edziennik/usos/data/UsosApi.kt | 12 ++-- .../data/api/edziennik/usos/data/UsosData.kt | 2 +- .../usos/firstlogin/UsosFirstLogin.kt | 23 +++++++ .../api/edziennik/usos/login/UsosLoginApi.kt | 53 +++++++++++++-- .../edziennik/ext/TextExtensions.kt | 7 ++ .../edziennik/ui/dialogs/OAuthLoginDialog.kt | 67 +++++++++++++++++++ .../edziennik/ui/login/LoginActivity.kt | 5 +- .../edziennik/ui/login/LoginFormFragment.kt | 12 +++- .../utils/managers/UserActionManager.kt | 43 +++++++++--- app/src/main/res/values/strings.xml | 1 + 14 files changed, 225 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index 3df74621..c0318251 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -99,3 +99,12 @@ const val PODLASIE_API_VERSION = "1.0.62" const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api" const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia" const val PODLASIE_API_LOGOUT_DEVICES_ENDPOINT = "/wyczyscUrzadzenia" + +const val USOS_API_OAUTH_REDIRECT_URL = "szkolny://redirect/usos" + +val USOS_API_SCOPES by lazy { listOf( + "offline_access", + "studies", + "grades", + "events", +) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt index 0b49e38b..097ed29e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.Usos import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback @@ -113,6 +114,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback) LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback) LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback) + LOGIN_TYPE_USOS -> Usos(app, profile, loginStore, taskCallback) else -> null } if (edziennikInterface == null) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt index 1dee14ba..f374db94 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -27,11 +27,21 @@ class DataUsos( override fun generateUserCode() = "USOS:TEST" + var schoolId: String? + get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId } + set(value) { loginStore.putLoginData("schoolId", value); mSchoolId = value } + private var mSchoolId: String? = null + var instanceUrl: String? get() { mInstanceUrl = mInstanceUrl ?: loginStore.getLoginData("instanceUrl", null); return mInstanceUrl } set(value) { loginStore.putLoginData("instanceUrl", value); mInstanceUrl = value } private var mInstanceUrl: String? = null + var oauthLoginResponse: String? + get() { mOauthLoginResponse = mOauthLoginResponse ?: loginStore.getLoginData("oauthLoginResponse", null); return mOauthLoginResponse } + set(value) { loginStore.putLoginData("oauthLoginResponse", value); mOauthLoginResponse = value } + private var mOauthLoginResponse: String? = null + var oauthConsumerKey: String? get() { mOauthConsumerKey = mOauthConsumerKey ?: loginStore.getLoginData("oauthConsumerKey", null); return mOauthConsumerKey } set(value) { loginStore.putLoginData("oauthConsumerKey", value); mOauthConsumerKey = value } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt index c97e3695..4ff9d04c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt @@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface @@ -71,9 +72,9 @@ class Usos( override fun getEvent(eventFull: EventFull) {} override fun firstLogin() { - /*UsosFirstLogin(data) { + UsosFirstLogin(data) { completed() - }*/ + } } override fun cancel() { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt index 6ffcd46a..ac73e29a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -78,7 +78,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { responseType: ResponseType, onSuccess: (data: T) -> Unit, ) { - val url = "${data.instanceUrl}/services/$service" + val url = "${data.instanceUrl}services/$service" d(tag, "Request: Usos/Api - $url") val formData = params.mapValues { valueToString(it.value) @@ -92,7 +92,11 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { "oauth_token" to (data.oauthTokenKey ?: ""), "oauth_version" to "1.0", ) - val signature = buildSignature("POST", url, formData + auth) + val signature = buildSignature( + method = "POST", + url = url, + params = formData + auth.filterKeys { it.startsWith("oauth_") }, + ) auth["oauth_signature"] = signature val authString = auth.map { @@ -152,10 +156,10 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { private fun processResponse( response: Response?, - data: T?, + data: T, onSuccess: (data: T) -> Unit, ) { - + onSuccess(data) } private fun processError( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt index bea52ea3..5ad199ff 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt @@ -41,7 +41,7 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { when (endpointId) { ENDPOINT_USOS_API_USER -> { data.startProgress(R.string.edziennik_progress_endpoint_student_info) - TemplateWebSample(data, lastSync, onSuccess) +// TemplateWebSample(data, lastSync, onSuccess) } else -> onSuccess(endpointId) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt new file mode 100644 index 00000000..3094980c --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-14. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin + +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi + +class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "UsosFirstLogin" + } + + private val api = UsosApi(data, null) + + init { + UsosLoginApi(data) { + + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt index bdf771c3..3027c334 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt @@ -4,10 +4,17 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login -import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_MISSING import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST +import pl.szczodrzynski.edziennik.data.api.USOS_API_OAUTH_REDIRECT_URL +import pl.szczodrzynski.edziennik.data.api.USOS_API_SCOPES import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.ext.Bundle +import pl.szczodrzynski.edziennik.ext.fromQueryString +import pl.szczodrzynski.edziennik.ext.toBundle +import pl.szczodrzynski.edziennik.ext.toQueryString +import pl.szczodrzynski.edziennik.utils.Utils.d class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { companion object { @@ -15,15 +22,47 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { } init { run { - if (data.profile == null) { - data.error(ApiError(TAG, ERROR_PROFILE_MISSING)) - return@run - } - if (data.isApiLoginValid()) { onSuccess() + } else if (data.oauthLoginResponse != null) { + login() } else { - data.error(ApiError(TAG, ERROR_USOS_OAUTH_LOGIN_REQUEST)) + authorize() } }} + + private fun authorize() { + val api = UsosApi(data, null) + + api.apiRequest( + tag = TAG, + service = "oauth/request_token", + params = mapOf( + "oauth_callback" to USOS_API_OAUTH_REDIRECT_URL, + "scopes" to USOS_API_SCOPES, + ), + responseType = UsosApi.ResponseType.PLAIN, + ) { + val response = it.fromQueryString() + data.oauthTokenKey = response["oauth_token"] + data.oauthTokenSecret = response["oauth_token_secret"] + + val authUrl = "${data.instanceUrl}services/oauth/authorize" + val authParams = mapOf( + "interactivity" to "confirm_user", + "oauth_token" to (data.oauthTokenKey ?: ""), + ) + val params = Bundle( + "authorizeUrl" to "$authUrl?${authParams.toQueryString()}", + "redirectUrl" to USOS_API_OAUTH_REDIRECT_URL, + "responseStoreKey" to "oauthLoginResponse", + "extras" to data.loginStore.data.toBundle(), + ) + data.error(ApiError(TAG, ERROR_USOS_OAUTH_LOGIN_REQUEST).withParams(params)) + } + } + + private fun login() { + d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse} (${data.oauthTokenSecret})") + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt index 84fe6631..d7717c7b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt @@ -18,6 +18,7 @@ import android.text.style.StyleSpan import androidx.annotation.PluralsRes import androidx.annotation.StringRes import com.mikepenz.materialdrawer.holder.StringHolder +import java.net.URLDecoder import java.net.URLEncoder fun CharSequence?.isNotNullNorEmpty(): Boolean { @@ -346,8 +347,14 @@ fun CharSequence.toStringHolder() = StringHolder(this) fun @receiver:StringRes Int.resolveString(context: Context) = context.getString(this) fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8").replace("+", "%20") +fun String.urlDecode(): String = URLDecoder.decode(this, "UTF-8") fun Map.toQueryString() = this .map { it.key.urlEncode() to it.value.urlEncode() } .sortedBy { it.first } .joinToString("&") { "${it.first}=${it.second}" } + +fun String.fromQueryString() = this + .split("&") + .map { it.split("=") } + .associate { it[0].urlDecode() to it[1].urlDecode() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt new file mode 100644 index 00000000..b777377e --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-14. + */ + +package pl.szczodrzynski.edziennik.ui.dialogs + +import android.annotation.SuppressLint +import android.graphics.Bitmap +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.FrameLayout +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.updateLayoutParams +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ext.dp +import pl.szczodrzynski.edziennik.ui.dialogs.base.ViewDialog +import pl.szczodrzynski.edziennik.utils.Utils.d + +class OAuthLoginDialog( + activity: AppCompatActivity, + private val authorizeUrl: String, + private val redirectUrl: String, + private val onSuccess: (responseUrl: String) -> Unit, + private val onFailure: (() -> Unit)?, + onShowListener: ((tag: String) -> Unit)? = null, + onDismissListener: ((tag: String) -> Unit)? = null, +) : ViewDialog(activity, onShowListener, onDismissListener) { + + override val TAG = "OAuthLoginDialog" + + override fun getTitleRes() = R.string.oauth_dialog_title + override fun getPositiveButtonText() = R.string.close + + private var isSuccessful = false + + @SuppressLint("SetJavaScriptEnabled") + override fun getRootView(): WebView { + val webView = WebView(activity) + webView.webViewClient = object : WebViewClient() { + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + d(TAG, "Navigating to $url") + if (url.startsWith(redirectUrl)) { + isSuccessful = true + onSuccess(url) + dismiss() + } + } + } + webView.settings.javaScriptEnabled = true + return webView + } + + override suspend fun onShow() { + dialog.window?.setLayout(MATCH_PARENT, MATCH_PARENT) + root.minimumHeight = activity.windowManager.defaultDisplay?.height?.div(2) ?: 300.dp + root.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + root.loadUrl(authorizeUrl) + } + + override fun onDismiss() { + root.stopLoading() + if (!isSuccessful) + onFailure?.invoke() + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginActivity.kt index 61aa4520..08d4917d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginActivity.kt @@ -31,6 +31,7 @@ class LoginActivity : AppCompatActivity(), CoroutineScope { private val app: App by lazy { applicationContext as App } private lateinit var b: LoginActivityBinding lateinit var navOptions: NavOptions + lateinit var navOptionsBuilder: NavOptions.Builder val nav by lazy { Navigation.findNavController(this, R.id.nav_host_fragment) } val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) } val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout } @@ -87,12 +88,12 @@ class LoginActivity : AppCompatActivity(), CoroutineScope { super.onCreate(savedInstanceState) setTheme(R.style.AppTheme_Light) - navOptions = NavOptions.Builder() + navOptionsBuilder = NavOptions.Builder() .setEnterAnim(R.anim.slide_in_right) .setExitAnim(R.anim.slide_out_left) .setPopEnterAnim(R.anim.slide_in_left) .setPopExitAnim(R.anim.slide_out_right) - .build() + navOptions = navOptionsBuilder.build() b = LoginActivityBinding.inflate(layoutInflater) setContentView(b.root) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt index b403568b..12daadcd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt @@ -14,6 +14,8 @@ import android.widget.Toast import androidx.core.view.isVisible import androidx.core.widget.addTextChangedListener import androidx.fragment.app.Fragment +import androidx.navigation.NavOptions +import androidx.navigation.navOptions import androidx.viewbinding.ViewBinding import com.google.android.material.textfield.TextInputLayout import com.mikepenz.iconics.IconicsDrawable @@ -304,6 +306,14 @@ class LoginFormFragment : Fragment(), CoroutineScope { if (hasErrors) return - nav.navigate(R.id.loginProgressFragment, payload, activity.navOptions) + val navOptions = + if (credentials.isEmpty()) + activity.navOptionsBuilder + .setPopUpTo(R.id.loginPlatformListFragment, inclusive = false) + .build() + else + activity.navOptions + + nav.navigate(R.id.loginProgressFragment, payload, navOptions) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index bbdb8602..c848c47a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog +import pl.szczodrzynski.edziennik.ui.dialogs.OAuthLoginDialog import pl.szczodrzynski.edziennik.utils.Utils.d class UserActionManager(val app: App) { @@ -89,9 +90,13 @@ class UserActionManager(val app: App) { onFailure: (() -> Unit)? = null ) { d(TAG, "Running user action ($type) with params: ${params?.toJsonObject()}") - when (type) { + val isSuccessful = when (type) { UserActionRequiredEvent.CAPTCHA_LIBRUS -> executeLibrus(activity, profileId, params, onSuccess, onFailure) UserActionRequiredEvent.OAUTH_USOS -> executeOauth(activity, profileId, params, onSuccess, onFailure) + else -> false + } + if (!isSuccessful) { + onFailure?.invoke() } } @@ -101,9 +106,9 @@ class UserActionManager(val app: App) { params: Bundle?, onSuccess: ((params: Bundle) -> Unit)?, onFailure: (() -> Unit)?, - ) { + ): Boolean { if (profileId == null) - return + return false val extras = params?.getBundle("extras") // show captcha dialog // use passed onSuccess listener, else sync profile @@ -117,14 +122,14 @@ class UserActionManager(val app: App) { if (extras != null) args.putAll(extras) - if (onSuccess != null) { + if (onSuccess != null) onSuccess(args) - } else { + else EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) - } }, - onFailure = onFailure + onFailure = onFailure, ).show() + return true } private fun executeOauth( @@ -133,10 +138,30 @@ class UserActionManager(val app: App) { params: Bundle?, onSuccess: ((params: Bundle) -> Unit)?, onFailure: (() -> Unit)?, - ) { + ): Boolean { if (profileId == null || params == null) - return + return false val extras = params.getBundle("extras") + val storeKey = params.getString("responseStoreKey") ?: return false + OAuthLoginDialog( + activity = activity, + authorizeUrl = params.getString("authorizeUrl") ?: return false, + redirectUrl = params.getString("redirectUrl") ?: return false, + onSuccess = { responseUrl -> + val args = Bundle( + storeKey to responseUrl, + ) + if (extras != null) + args.putAll(extras) + + if (onSuccess != null) + onSuccess(args) + else + EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) + }, + onFailure = onFailure, + ).show() + return true } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 393248c9..7aae860c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1542,4 +1542,5 @@ Logowanie z użyciem przeglądarki TODO USOS - wymagane logowanie z użyciem przeglądarki + Zaloguj się From 7ded400a30e6aa8a39fc417648cd119649f5838c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 15 Oct 2022 19:07:12 +0200 Subject: [PATCH 09/53] [API/Usos] Implement first login. --- app/src/main/AndroidManifest.xml | 4 + .../edziennik/data/api/Errors.kt | 3 + .../data/api/edziennik/usos/DataUsos.kt | 9 ++- .../data/api/edziennik/usos/data/UsosApi.kt | 16 ++-- .../usos/firstlogin/UsosFirstLogin.kt | 63 ++++++++++++++- .../api/edziennik/usos/login/UsosLoginApi.kt | 73 +++++++++++++----- .../edziennik/ext/JsonExtensions.kt | 10 ++- .../edziennik/ext/TextExtensions.kt | 1 + .../edziennik/ui/dialogs/OAuthLoginDialog.kt | 67 ---------------- .../edziennik/ui/login/LoginInfo.kt | 2 +- .../ui/login/oauth/OAuthLoginActivity.kt | 64 +++++++++++++++ .../ui/login/oauth/OAuthLoginResult.kt | 10 +++ .../utils/managers/UserActionManager.kt | 49 +++++++----- app/src/main/res/drawable/login_logo_usos.png | Bin 15635 -> 16760 bytes .../main/res/drawable/login_mode_usos_api.png | Bin 0 -> 5392 bytes 15 files changed, 255 insertions(+), 116 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt create mode 100644 app/src/main/res/drawable/login_mode_usos_api.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c5c273b4..fb824573 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -157,6 +157,10 @@ android:configChanges="orientation|keyboardHidden" android:exported="false" android:theme="@style/Base.Theme.AppCompat" /> + diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 617ef5ed..10405e5f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -205,6 +205,9 @@ const val ERROR_PODLASIE_API_OTHER = 631 const val ERROR_PODLASIE_API_DATA_MISSING = 632 const val ERROR_USOS_OAUTH_LOGIN_REQUEST = 701 +const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702 +const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703 +const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704 const val ERROR_TEMPLATE_WEB_OTHER = 801 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt index f374db94..0fd1b2ba 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -16,7 +16,7 @@ class DataUsos( loginStore: LoginStore, ) : Data(app, profile, loginStore) { - fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null + fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null && oauthTokenIsUser override fun satisfyLoginMethods() { loginMethods.clear() @@ -25,7 +25,7 @@ class DataUsos( } } - override fun generateUserCode() = "USOS:TEST" + override fun generateUserCode() = "$schoolId:${studentNumber ?: studentId}" var schoolId: String? get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId } @@ -62,6 +62,11 @@ class DataUsos( set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value } private var mOauthTokenSecret: String? = null + var oauthTokenIsUser: Boolean + get() { mOauthTokenIsUser = mOauthTokenIsUser ?: loginStore.getLoginData("oauthTokenIsUser", false); return mOauthTokenIsUser ?: false } + set(value) { loginStore.putLoginData("oauthTokenIsUser", value); mOauthTokenIsUser = value } + private var mOauthTokenIsUser: Boolean? = null + var studentId: String? get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId } set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt index ac73e29a..1d3ab69c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -76,7 +76,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { service: String, params: Map, responseType: ResponseType, - onSuccess: (data: T) -> Unit, + onSuccess: (data: T, response: Response?) -> Unit, ) { val url = "${data.instanceUrl}services/$service" d(tag, "Request: Usos/Api - $url") @@ -123,10 +123,10 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { private fun getCallback( tag: String, responseType: ResponseType, - onSuccess: (data: T) -> Unit, + onSuccess: (data: T, response: Response?) -> Unit, ) = when (responseType) { ResponseType.OBJECT -> object : JsonCallbackHandler() { - override fun onSuccess(data: JsonObject?, response: Response?) { + override fun onSuccess(data: JsonObject?, response: Response) { processResponse(response, data as T, onSuccess) } @@ -135,7 +135,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } } ResponseType.ARRAY -> object : JsonArrayCallbackHandler() { - override fun onSuccess(data: JsonArray?, response: Response?) { + override fun onSuccess(data: JsonArray?, response: Response) { processResponse(response, data as T, onSuccess) } @@ -144,7 +144,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } } ResponseType.PLAIN -> object : TextCallbackHandler() { - override fun onSuccess(data: String?, response: Response?) { + override fun onSuccess(data: String?, response: Response) { processResponse(response, data as T, onSuccess) } @@ -155,11 +155,11 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } private fun processResponse( - response: Response?, + response: Response, data: T, - onSuccess: (data: T) -> Unit, + onSuccess: (data: T, response: Response?) -> Unit, ) { - onSuccess(data) + onSuccess(data, response) } private fun processError( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt index 3094980c..ad51cf92 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt @@ -4,9 +4,18 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin +import com.google.gson.JsonObject +import org.greenrobot.eventbus.EventBus +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS +import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi +import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.ext.* class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { companion object { @@ -16,8 +25,60 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { private val api = UsosApi(data, null) init { - UsosLoginApi(data) { + val loginStoreId = data.loginStore.id + val loginStoreType = LOGIN_TYPE_USOS + var firstProfileId = loginStoreId + UsosLoginApi(data) { + api.apiRequest( + tag = TAG, + service = "users/user", + params = mapOf( + "fields" to listOf( + "id", + "first_name", + "last_name", + "student_number", + "student_programmes" to listOf( + "programme" to listOf("id"), + ), + ), + ), + responseType = UsosApi.ResponseType.OBJECT, + ) { json, response -> + val programmes = json.getJsonArray("student_programmes") + if (programmes.isNullOrEmpty()) { + data.error(ApiError(TAG, ERROR_USOS_NO_STUDENT_PROGRAMMES) + .withApiResponse(json) + .withResponse(response)) + return@apiRequest + } + + val firstName = json.getString("first_name") + val lastName = json.getString("last_name") + val studentName = buildFullName(firstName, lastName) + + val profile = Profile( + id = firstProfileId++, + loginStoreId = loginStoreId, loginStoreType = loginStoreType, + name = studentName, + subname = data.schoolId, + studentNameLong = studentName, + studentNameShort = studentName.getShortName(), + accountName = null, // student account + studentData = JsonObject( + "studentId" to json.getInt("id"), + "studentNumber" to json.getInt("student_number"), + ), + ).also { + it.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id") + } + + EventBus.getDefault().postSticky( + FirstLoginFinishedEvent(listOf(profile), data.loginStore), + ) + onSuccess() + } } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt index 3027c334..f49c0cea 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt @@ -4,9 +4,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login -import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST -import pl.szczodrzynski.edziennik.data.api.USOS_API_OAUTH_REDIRECT_URL -import pl.szczodrzynski.edziennik.data.api.USOS_API_SCOPES +import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -21,19 +19,21 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { private const val TAG = "UsosLoginApi" } - init { run { - if (data.isApiLoginValid()) { - onSuccess() - } else if (data.oauthLoginResponse != null) { - login() - } else { - authorize() + private val api = UsosApi(data, null) + + init { + run { + if (data.isApiLoginValid()) { + onSuccess() + } else if (data.oauthLoginResponse != null) { + login() + } else { + authorize() + } } - }} + } private fun authorize() { - val api = UsosApi(data, null) - api.apiRequest( tag = TAG, service = "oauth/request_token", @@ -42,10 +42,11 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { "scopes" to USOS_API_SCOPES, ), responseType = UsosApi.ResponseType.PLAIN, - ) { - val response = it.fromQueryString() - data.oauthTokenKey = response["oauth_token"] - data.oauthTokenSecret = response["oauth_token_secret"] + ) { text, _ -> + val authorizeData = text.fromQueryString() + data.oauthTokenKey = authorizeData["oauth_token"] + data.oauthTokenSecret = authorizeData["oauth_token_secret"] + data.oauthTokenIsUser = false val authUrl = "${data.instanceUrl}services/oauth/authorize" val authParams = mapOf( @@ -63,6 +64,42 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { } private fun login() { - d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse} (${data.oauthTokenSecret})") + d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse}") + + val authorizeResponse = data.oauthLoginResponse?.fromQueryString() + ?: return // checked in init {} + if (authorizeResponse["oauth_token"] != data.oauthTokenKey) { + // got different token + data.error(ApiError(TAG, ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN) + .withApiResponse(data.oauthLoginResponse)) + return + } + val verifier = authorizeResponse["oauth_verifier"] + if (verifier.isNullOrBlank()) { + data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE) + .withApiResponse(data.oauthLoginResponse)) + return + } + + api.apiRequest( + tag = TAG, + service = "oauth/access_token", + params = mapOf( + "oauth_verifier" to verifier, + ), + responseType = UsosApi.ResponseType.PLAIN, + ) { text, response -> + val accessData = text.fromQueryString() + data.oauthTokenKey = accessData["oauth_token"] + data.oauthTokenSecret = accessData["oauth_token_secret"] + data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null + + if (!data.oauthTokenIsUser) + data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE) + .withApiResponse(text) + .withResponse(response)) + else + onSuccess() + } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt index 9f0db8ad..14d25b48 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt @@ -10,6 +10,8 @@ import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.gson.JsonPrimitive +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract fun JsonObject?.get(key: String): JsonElement? = this?.get(key) @@ -93,7 +95,13 @@ fun JsonArray(vararg properties: Any?): JsonArray { } } -fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0 +@OptIn(ExperimentalContracts::class) +fun JsonArray?.isNullOrEmpty(): Boolean { + contract { + returns(false) implies (this@isNullOrEmpty != null) + } + return this == null || this.isEmpty +} operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o) operator fun JsonArray.plusAssign(o: String) = this.add(o) operator fun JsonArray.plusAssign(o: Char) = this.add(o) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt index d7717c7b..adb6fe55 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TextExtensions.kt @@ -355,6 +355,7 @@ fun Map.toQueryString() = this .joinToString("&") { "${it.first}=${it.second}" } fun String.fromQueryString() = this + .substringAfter('?') .split("&") .map { it.split("=") } .associate { it[0].urlDecode() to it[1].urlDecode() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt deleted file mode 100644 index b777377e..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/OAuthLoginDialog.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2022-10-14. - */ - -package pl.szczodrzynski.edziennik.ui.dialogs - -import android.annotation.SuppressLint -import android.graphics.Bitmap -import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.webkit.WebView -import android.webkit.WebViewClient -import android.widget.FrameLayout -import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.updateLayoutParams -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.ext.dp -import pl.szczodrzynski.edziennik.ui.dialogs.base.ViewDialog -import pl.szczodrzynski.edziennik.utils.Utils.d - -class OAuthLoginDialog( - activity: AppCompatActivity, - private val authorizeUrl: String, - private val redirectUrl: String, - private val onSuccess: (responseUrl: String) -> Unit, - private val onFailure: (() -> Unit)?, - onShowListener: ((tag: String) -> Unit)? = null, - onDismissListener: ((tag: String) -> Unit)? = null, -) : ViewDialog(activity, onShowListener, onDismissListener) { - - override val TAG = "OAuthLoginDialog" - - override fun getTitleRes() = R.string.oauth_dialog_title - override fun getPositiveButtonText() = R.string.close - - private var isSuccessful = false - - @SuppressLint("SetJavaScriptEnabled") - override fun getRootView(): WebView { - val webView = WebView(activity) - webView.webViewClient = object : WebViewClient() { - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - d(TAG, "Navigating to $url") - if (url.startsWith(redirectUrl)) { - isSuccessful = true - onSuccess(url) - dismiss() - } - } - } - webView.settings.javaScriptEnabled = true - return webView - } - - override suspend fun onShow() { - dialog.window?.setLayout(MATCH_PARENT, MATCH_PARENT) - root.minimumHeight = activity.windowManager.defaultDisplay?.height?.div(2) ?: 300.dp - root.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) - root.loadUrl(authorizeUrl) - } - - override fun onDismiss() { - root.stopLoading() - if (!isSuccessful) - onFailure?.invoke() - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt index 15a7021d..8b605734 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt @@ -324,7 +324,7 @@ object LoginInfo { Mode( loginMode = LOGIN_MODE_USOS_OAUTH, name = R.string.login_mode_usos_oauth, - icon = R.drawable.login_logo_usos, + icon = R.drawable.login_mode_usos_api, guideText = R.string.login_mode_usos_oauth_guide, isPlatformSelection = true, credentials = listOf(), diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt new file mode 100644 index 00000000..c80c3d82 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginActivity.kt @@ -0,0 +1,64 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-15. + */ + +package pl.szczodrzynski.edziennik.ui.login.oauth + +import android.annotation.SuppressLint +import android.graphics.Bitmap +import android.os.Bundle +import android.view.ViewGroup.LayoutParams.MATCH_PARENT +import android.webkit.WebView +import android.webkit.WebViewClient +import android.widget.FrameLayout +import androidx.appcompat.app.AppCompatActivity +import org.greenrobot.eventbus.EventBus +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.Utils.d + +class OAuthLoginActivity : AppCompatActivity() { + companion object { + private const val TAG = "OAuthLoginActivity" + } + + private var isSuccessful = false + + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setTitle(R.string.oauth_dialog_title) + + val authorizeUrl = intent.getStringExtra("authorizeUrl") ?: return + val redirectUrl = intent.getStringExtra("redirectUrl") ?: return + + val webView = WebView(this) + webView.webViewClient = object : WebViewClient() { + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + d(TAG, "Navigating to $url") + if (url.startsWith(redirectUrl)) { + isSuccessful = true + EventBus.getDefault().post(OAuthLoginResult( + isError = false, + responseUrl = url, + )) + finish() + } + } + } + webView.settings.javaScriptEnabled = true + webView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + setContentView(webView) + + webView.loadUrl(authorizeUrl) + } + + override fun onDestroy() { + super.onDestroy() + if (!isSuccessful) + EventBus.getDefault().post(OAuthLoginResult( + isError = false, + responseUrl = null, + )) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt new file mode 100644 index 00000000..108c0c8e --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/oauth/OAuthLoginResult.kt @@ -0,0 +1,10 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-15. + */ + +package pl.szczodrzynski.edziennik.ui.login.oauth + +data class OAuthLoginResult( + val isError: Boolean, + val responseUrl: String?, +) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index c848c47a..3117c650 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -11,6 +11,8 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.app.NotificationCompat import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R @@ -21,7 +23,8 @@ import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog -import pl.szczodrzynski.edziennik.ui.dialogs.OAuthLoginDialog +import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginActivity +import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginResult import pl.szczodrzynski.edziennik.utils.Utils.d class UserActionManager(val app: App) { @@ -143,25 +146,35 @@ class UserActionManager(val app: App) { return false val extras = params.getBundle("extras") val storeKey = params.getString("responseStoreKey") ?: return false + params.getString("authorizeUrl") ?: return false + params.getString("redirectUrl") ?: return false - OAuthLoginDialog( - activity = activity, - authorizeUrl = params.getString("authorizeUrl") ?: return false, - redirectUrl = params.getString("redirectUrl") ?: return false, - onSuccess = { responseUrl -> - val args = Bundle( - storeKey to responseUrl, - ) - if (extras != null) - args.putAll(extras) + var listener: Any? = null + listener = object { + @Subscribe(threadMode = ThreadMode.MAIN) + fun onOAuthLoginResult(result: OAuthLoginResult) { + EventBus.getDefault().unregister(listener) + when { + result.isError -> onFailure?.invoke() + result.responseUrl != null -> { + val args = Bundle( + storeKey to result.responseUrl, + ) + if (extras != null) + args.putAll(extras) - if (onSuccess != null) - onSuccess(args) - else - EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) - }, - onFailure = onFailure, - ).show() + if (onSuccess != null) + onSuccess(args) + else + EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) + } + } + } + } + EventBus.getDefault().register(listener) + + val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(params) + activity.startActivity(intent) return true } } diff --git a/app/src/main/res/drawable/login_logo_usos.png b/app/src/main/res/drawable/login_logo_usos.png index 7c376bddaf28d4462635115fed43a00a484a8a3c..98d95b3496facdc49f2236148d5fa501ce1d2d0c 100644 GIT binary patch literal 16760 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 diff --git a/app/src/main/res/drawable/login_mode_usos_api.png b/app/src/main/res/drawable/login_mode_usos_api.png new file mode 100644 index 0000000000000000000000000000000000000000..6ec32631ce9eb9390d4c71a0b1f308d20e903948 GIT binary patch literal 5392 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 u5nlQ5*SGm#+$-Utt>PQQ|0ni;8~zU Date: Sat, 15 Oct 2022 21:24:30 +0200 Subject: [PATCH 10/53] [API/Login] Make user action handling more universal. --- .../szczodrzynski/edziennik/MainActivity.kt | 16 +- .../edziennik/data/api/ApiService.kt | 18 +- .../edziennik/data/api/Constants.kt | 3 + .../edziennik/data/api/Errors.kt | 7 +- .../data/api/edziennik/librus/Librus.kt | 2 + .../librus/login/LibrusLoginPortal.kt | 22 ++- .../edziennik/mobidziennik/Mobidziennik.kt | 2 + .../data/api/edziennik/podlasie/Podlasie.kt | 5 + .../data/api/edziennik/template/Template.kt | 5 + .../edziennik/data/api/edziennik/usos/Usos.kt | 5 + .../api/edziennik/usos/login/UsosLoginApi.kt | 18 +- .../data/api/edziennik/vulcan/Vulcan.kt | 2 + .../api/events/UserActionRequiredEvent.kt | 16 +- .../data/api/interfaces/EdziennikCallback.kt | 2 + .../edziennik/data/api/models/Data.kt | 15 +- .../edziennik/ext/BundleExtensions.kt | 10 ++ ...tchaDialog.kt => RecaptchaPromptDialog.kt} | 14 +- .../edziennik/ui/home/cards/HomeDebugCard.kt | 7 +- .../edziennik/ui/login/LoginInfo.kt | 1 - .../ui/login/LoginProgressFragment.kt | 25 ++- .../utils/managers/UserActionManager.kt | 164 ++++++++---------- app/src/main/res/layout/card_home_debug.xml | 7 - app/src/main/res/values/errors.xml | 14 -- 23 files changed, 206 insertions(+), 174 deletions(-) rename app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/{LibrusCaptchaDialog.kt => RecaptchaPromptDialog.kt} (88%) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 30c3a3e0..000f9be6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -34,6 +34,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import pl.droidsonroids.gif.GifDrawable +import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.* @@ -69,6 +70,7 @@ import pl.szczodrzynski.edziennik.ui.grades.editor.GradesEditorFragment import pl.szczodrzynski.edziennik.ui.home.HomeFragment import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment import pl.szczodrzynski.edziennik.ui.login.LoginActivity +import pl.szczodrzynski.edziennik.ui.login.LoginProgressFragment import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment @@ -83,6 +85,7 @@ import pl.szczodrzynski.edziennik.utils.* import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.dpToPx import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type +import pl.szczodrzynski.edziennik.utils.managers.UserActionManager import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.NavTarget import pl.szczodrzynski.navlib.* @@ -853,7 +856,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { @Subscribe(threadMode = ThreadMode.MAIN) fun onUserActionRequiredEvent(event: UserActionRequiredEvent) { - app.userActionManager.execute(this, event.profileId, event.type, event.params) + app.userActionManager.execute(this, event, UserActionManager.UserActionCallback()) } private fun fragmentToSyncName(currentFragment: Int): Int { @@ -911,12 +914,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope { false } "userActionRequired" -> { - app.userActionManager.execute( - this, - extras.getInt("profileId"), - extras.getInt("type"), - extras.getBundle("params"), + val event = UserActionRequiredEvent( + profileId = extras.getInt("profileId"), + type = extras.getEnum("type") ?: return, + params = extras.getBundle("params") ?: return, + errorText = 0, ) + app.userActionManager.execute(this, event, UserActionManager.UserActionCallback()) true } "createManualEvent" -> { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/ApiService.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/ApiService.kt index f68e8840..0d9fe92c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/ApiService.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/ApiService.kt @@ -84,19 +84,21 @@ class ApiService : Service() { runTask() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { + app.userActionManager.sendToUser(event) + taskRunning?.cancel() + clearTask() + runTask() + } + override fun onError(apiError: ApiError) { lastEventTime = System.currentTimeMillis() d(TAG, "Task $taskRunningId threw an error - $apiError") apiError.profileId = taskProfileId - if (app.userActionManager.requiresUserAction(apiError)) { - app.userActionManager.sendToUser(apiError) - } - else { - EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError)) - errorList.add(apiError) - apiError.throwable?.printStackTrace() - } + EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError)) + errorList.add(apiError) + apiError.throwable?.printStackTrace() if (apiError.isCritical) { taskRunning?.cancel() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt index c0318251..c29b8698 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Constants.kt @@ -59,6 +59,9 @@ const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action=" const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile" const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik" +const val LIBRUS_PORTAL_RECAPTCHA_KEY = "6Lf48moUAAAAAB9ClhdvHr46gRWR" +const val LIBRUS_PORTAL_RECAPTCHA_REFERER = "https://portal.librus.pl/rodzina/login" + val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 10405e5f..b4e892e6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -58,11 +58,7 @@ const val ERROR_INVALID_LOGIN_MODE = 110 const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111 const val ERROR_NOT_IMPLEMENTED = 112 const val ERROR_FILE_DOWNLOAD = 113 - -const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115 - -const val ERROR_CAPTCHA_NEEDED = 3000 -const val ERROR_CAPTCHA_LIBRUS_PORTAL = 3001 +const val ERROR_REQUIRES_USER_ACTION = 114 const val ERROR_API_PDO_ERROR = 5000 const val ERROR_API_INVALID_CLIENT = 5001 @@ -204,7 +200,6 @@ const val ERROR_PODLASIE_API_NO_TOKEN = 630 const val ERROR_PODLASIE_API_OTHER = 631 const val ERROR_PODLASIE_API_DATA_MISSING = 632 -const val ERROR_USOS_OAUTH_LOGIN_REQUEST = 701 const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702 const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703 const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt index abf3ac5f..0830752f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt @@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -162,6 +163,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { return object : EdziennikCallback { override fun onCompleted() { callback.onCompleted() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) } override fun onProgress(step: Float) { callback.onProgress(step) } override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) } override fun onError(apiError: ApiError) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt index ed01d01f..ab21c692 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt @@ -10,6 +10,7 @@ import im.wangchao.mhttp.callback.TextCallbackHandler import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d @@ -148,12 +149,23 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) { val error = if (response.code() == 200) null else json.getJsonArray("errors")?.getString(0) ?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString + + if (error?.contains("robotem") == true || json.getBoolean("captchaRequired") == true) { + data.requireUserAction( + type = UserActionRequiredEvent.Type.RECAPTCHA, + params = Bundle( + "siteKey" to LIBRUS_PORTAL_RECAPTCHA_KEY, + "referer" to LIBRUS_PORTAL_RECAPTCHA_REFERER, + ), + errorText = R.string.notification_user_action_required_captcha_librus, + ) + return + } + error?.let { code -> when { code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN - // this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set - code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR }.let { errorCode -> @@ -163,12 +175,6 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) { return } } - if (json.getBoolean("captchaRequired") == true) { - data.error(ApiError(TAG, ERROR_CAPTCHA_LIBRUS_PORTAL) - .withResponse(response) - .withApiResponse(json)) - return - } authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL)) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt index e19fabca..0144ad5d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.Mobidzien import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.* import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin.MobidziennikFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLogin +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -142,6 +143,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { return object : EdziennikCallback { override fun onCompleted() { callback.onCompleted() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) } override fun onProgress(step: Float) { callback.onProgress(step) } override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) } override fun onError(apiError: ApiError) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt index d7ec441f..0eaaebae 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieData import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin.PodlasieFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogin import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -142,6 +143,10 @@ class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore, callback.onCompleted() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { + callback.onRequiresUserAction(event) + } + override fun onProgress(step: Float) { callback.onProgress(step) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt index 843d36e9..8abf079f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.CODE_INTERNAL_LIBRUS_ACCOUNT_410 import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateData import pl.szczodrzynski.edziennik.data.api.edziennik.template.firstlogin.TemplateFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLogin +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -108,6 +109,10 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, callback.onCompleted() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { + callback.onRequiresUserAction(event) + } + override fun onProgress(step: Float) { callback.onProgress(step) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt index 4ff9d04c..d676d006 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt @@ -8,6 +8,7 @@ import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -88,6 +89,10 @@ class Usos( callback.onCompleted() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { + callback.onRequiresUserAction(event) + } + override fun onProgress(step: Float) { callback.onProgress(step) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt index f49c0cea..11172d7d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt @@ -4,9 +4,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login +import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.fromQueryString @@ -53,13 +55,16 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { "interactivity" to "confirm_user", "oauth_token" to (data.oauthTokenKey ?: ""), ) - val params = Bundle( - "authorizeUrl" to "$authUrl?${authParams.toQueryString()}", - "redirectUrl" to USOS_API_OAUTH_REDIRECT_URL, - "responseStoreKey" to "oauthLoginResponse", - "extras" to data.loginStore.data.toBundle(), + data.requireUserAction( + type = UserActionRequiredEvent.Type.OAUTH, + params = Bundle( + "authorizeUrl" to "$authUrl?${authParams.toQueryString()}", + "redirectUrl" to USOS_API_OAUTH_REDIRECT_URL, + "responseStoreKey" to "oauthLoginResponse", + "extras" to data.loginStore.data.toBundle(), + ), + errorText = R.string.notification_user_action_required_oauth_usos, ) - data.error(ApiError(TAG, ERROR_USOS_OAUTH_LOGIN_REQUEST).withParams(params)) } } @@ -93,6 +98,7 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { data.oauthTokenKey = accessData["oauth_token"] data.oauthTokenSecret = accessData["oauth_token_secret"] data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null + data.loginStore.removeLoginData("oauthLoginResponse") if (!data.oauthTokenIsUser) data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt index 64c87bf6..37af4b69 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt @@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError @@ -179,6 +180,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { return object : EdziennikCallback { override fun onCompleted() { callback.onCompleted() } + override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) } override fun onProgress(step: Float) { callback.onProgress(step) } override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) } override fun onError(apiError: ApiError) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt index da68f3e8..3995842a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/events/UserActionRequiredEvent.kt @@ -6,12 +6,14 @@ package pl.szczodrzynski.edziennik.data.api.events import android.os.Bundle -data class UserActionRequiredEvent(val profileId: Int, val type: Int, val params: Bundle?) { - companion object { - const val LOGIN_DATA_MOBIDZIENNIK = 101 - const val LOGIN_DATA_LIBRUS = 102 - const val LOGIN_DATA_VULCAN = 104 - const val CAPTCHA_LIBRUS = 202 - const val OAUTH_USOS = 701 +data class UserActionRequiredEvent( + val profileId: Int?, + val type: Type, + val params: Bundle, + val errorText: Int, +) { + enum class Type { + RECAPTCHA, + OAUTH, } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt index c1c878b4..4943ff1e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt @@ -4,6 +4,7 @@ package pl.szczodrzynski.edziennik.data.api.interfaces +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.Feature import pl.szczodrzynski.edziennik.data.api.models.LoginMethod @@ -14,4 +15,5 @@ import pl.szczodrzynski.edziennik.data.api.models.LoginMethod */ interface EdziennikCallback : EndpointCallback { fun onCompleted() + fun onRequiresUserAction(event: UserActionRequiredEvent) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt index ea53112a..c02c666a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt @@ -1,5 +1,6 @@ package pl.szczodrzynski.edziennik.data.api.models +import android.os.Bundle import android.util.LongSparseArray import android.util.SparseArray import androidx.core.util.set @@ -12,7 +13,8 @@ import pl.szczodrzynski.edziennik.BuildConfig import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE import pl.szczodrzynski.edziennik.data.api.Regexes.MESSAGE_META -import pl.szczodrzynski.edziennik.data.api.interfaces.EndpointCallback +import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent +import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.ext.* @@ -37,7 +39,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt /** * A callback passed to all [Feature]s and [LoginMethod]s */ - lateinit var callback: EndpointCallback + lateinit var callback: EdziennikCallback /** * A list of [LoginMethod]s *already fulfilled* during this sync. @@ -374,6 +376,15 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt callback.onError(apiError) } + fun requireUserAction(type: UserActionRequiredEvent.Type, params: Bundle, errorText: Int) { + callback.onRequiresUserAction(UserActionRequiredEvent( + profileId = profile?.id, + type = type, + params = params, + errorText = errorText, + )) + } + fun progress(step: Float) { callback.onProgress(step) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt index cc6488bd..037d78f5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt @@ -22,6 +22,15 @@ fun Bundle?.getFloat(key: String, defaultValue: Float): Float { fun Bundle?.getString(key: String, defaultValue: String): String { return this?.getString(key, defaultValue) ?: defaultValue } +inline fun > Bundle?.getEnum(key: String): E? { + return this?.getString(key)?.let { + try { + enumValueOf(it) + } catch (e: Exception) { + null + } + } +} fun Bundle?.getIntOrNull(key: String): Int? { return this?.get(key) as? Int @@ -48,6 +57,7 @@ fun Bundle(vararg properties: Pair): Bundle { is Bundle -> putBundle(property.first, property.second as Bundle) is Parcelable -> putParcelable(property.first, property.second as Parcelable) is Array<*> -> putParcelableArray(property.first, property.second as Array) + is Enum<*> -> putString(property.first, (property.second as Enum<*>).name) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/LibrusCaptchaDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/RecaptchaPromptDialog.kt similarity index 88% rename from app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/LibrusCaptchaDialog.kt rename to app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/RecaptchaPromptDialog.kt index 12ad0e37..a927347d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/LibrusCaptchaDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/captcha/RecaptchaPromptDialog.kt @@ -13,14 +13,16 @@ import pl.szczodrzynski.edziennik.databinding.RecaptchaViewBinding import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog -class LibrusCaptchaDialog( +class RecaptchaPromptDialog( activity: AppCompatActivity, + private val siteKey: String, + private val referer: String, private val onSuccess: (recaptchaCode: String) -> Unit, - private val onFailure: (() -> Unit)?, + private val onCancel: (() -> Unit)?, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, ) : BindingDialog(activity, onShowListener, onDismissListener) { - override val TAG = "LibrusCaptchaDialog" + override val TAG = "RecaptchaPromptDialog" override fun getTitleRes(): Int? = null override fun inflate(layoutInflater: LayoutInflater) = @@ -46,8 +48,8 @@ class LibrusCaptchaDialog( b.progress.visibility = View.VISIBLE RecaptchaDialog( activity, - siteKey = "6Lf48moUAAAAAB9ClhdvHr46gRWR-CN31CXQPG2U", - referer = "https://portal.librus.pl/rodzina/login", + siteKey = siteKey, + referer = referer, onSuccess = { recaptchaCode -> b.checkbox.background = checkboxBackground b.checkbox.foreground = checkboxForeground @@ -67,6 +69,6 @@ class LibrusCaptchaDialog( override fun onDismiss() { if (!success) - onFailure?.invoke() + onCancel?.invoke() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeDebugCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeDebugCard.kt index 329a677a..6947b74b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeDebugCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeDebugCard.kt @@ -27,7 +27,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.databinding.CardHomeDebugBinding import pl.szczodrzynski.edziennik.ext.dp import pl.szczodrzynski.edziennik.ext.onClick -import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog +import pl.szczodrzynski.edziennik.ui.captcha.RecaptchaPromptDialog import pl.szczodrzynski.edziennik.ui.home.HomeCard import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter import pl.szczodrzynski.edziennik.ui.home.HomeFragment @@ -85,11 +85,6 @@ class HomeDebugCard( app.startActivity(Chucker.getLaunchIntent(activity, 1)); } - b.librusCaptchaButton.onClick { - //app.startActivity(Intent(activity, LoginLibrusCaptchaActivity::class.java)) - LibrusCaptchaDialog(activity, onSuccess = {}, onFailure = {}).show() - } - b.getLogs.onClick { val logs = HyperLog.getDeviceLogsInFile(activity, true) val intent = Intent(Intent.ACTION_SEND) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt index 8b605734..774530f1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt @@ -65,7 +65,6 @@ object LoginInfo { errorCodes = mapOf( ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED to R.string.login_error_account_not_activated, ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password, - ERROR_CAPTCHA_LIBRUS_PORTAL to R.string.error_3001_reason ) ), /*Mode( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt index ee29575e..87a01008 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt @@ -19,7 +19,7 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.ERROR_CAPTCHA_NEEDED +import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION import pl.szczodrzynski.edziennik.data.api.LOGIN_NO_ARGUMENTS import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent @@ -29,6 +29,7 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding import pl.szczodrzynski.edziennik.ext.joinNotNullStrings +import pl.szczodrzynski.edziennik.utils.managers.UserActionManager import kotlin.coroutines.CoroutineContext import kotlin.math.max @@ -137,13 +138,21 @@ class LoginProgressFragment : Fragment(), CoroutineScope { return } - app.userActionManager.execute(activity, event.profileId, event.type, event.params, onSuccess = { params -> - args.putAll(params) - doFirstLogin(args) - }, onFailure = { - activity.error(ApiError(TAG, ERROR_CAPTCHA_NEEDED)) - nav.navigateUp() - }) + val callback = UserActionManager.UserActionCallback( + onSuccess = { data -> + args.putAll(data) + doFirstLogin(args) + }, + onFailure = { + activity.error(ApiError(TAG, ERROR_REQUIRES_USER_ACTION)) + nav.navigateUp() + }, + onCancel = { + nav.navigateUp() + }, + ) + + app.userActionManager.execute(activity, event, callback) } override fun onStart() { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt index 3117c650..3e8761c8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/UserActionManager.kt @@ -16,13 +16,10 @@ import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.ERROR_CAPTCHA_LIBRUS_PORTAL -import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_OAUTH_LOGIN_REQUEST import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent -import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.* -import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog +import pl.szczodrzynski.edziennik.ui.captcha.RecaptchaPromptDialog import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginActivity import pl.szczodrzynski.edziennik.ui.login.oauth.OAuthLoginResult import pl.szczodrzynski.edziennik.utils.Utils.d @@ -32,43 +29,31 @@ class UserActionManager(val app: App) { private const val TAG = "UserActionManager" } - fun requiresUserAction(apiError: ApiError) = when (apiError.errorCode) { - ERROR_CAPTCHA_LIBRUS_PORTAL -> true - ERROR_USOS_OAUTH_LOGIN_REQUEST -> true - else -> false - } - - fun sendToUser(apiError: ApiError) { - val type = when (apiError.errorCode) { - ERROR_CAPTCHA_LIBRUS_PORTAL -> UserActionRequiredEvent.CAPTCHA_LIBRUS - ERROR_USOS_OAUTH_LOGIN_REQUEST -> UserActionRequiredEvent.OAUTH_USOS - else -> 0 - } - + fun sendToUser(event: UserActionRequiredEvent) { if (EventBus.getDefault().hasSubscriberForEvent(UserActionRequiredEvent::class.java)) { - EventBus.getDefault().post(UserActionRequiredEvent(apiError.profileId ?: -1, type, apiError.params)) + EventBus.getDefault().post(event) return } val manager = app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - - val text = app.getString(when (type) { - UserActionRequiredEvent.CAPTCHA_LIBRUS -> R.string.notification_user_action_required_captcha_librus - UserActionRequiredEvent.OAUTH_USOS -> R.string.notification_user_action_required_oauth_usos - else -> R.string.notification_user_action_required_text - }, apiError.profileId) - + val text = app.getString(event.errorText, event.profileId) val intent = Intent( - app, - MainActivity::class.java, - "action" to "userActionRequired", - "profileId" to (apiError.profileId ?: -1), - "type" to type, - "params" to apiError.params, + app, + MainActivity::class.java, + "action" to "userActionRequired", + "profileId" to event.profileId, + "type" to event.type, + "params" to event.params, + ) + val pendingIntent = PendingIntent.getActivity( + app, + System.currentTimeMillis().toInt(), + intent, + PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag(), ) - val pendingIntent = PendingIntent.getActivity(app, System.currentTimeMillis().toInt(), intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag()) - val notification = NotificationCompat.Builder(app, app.notificationChannelsManager.userAttention.key) + val notification = + NotificationCompat.Builder(app, app.notificationChannelsManager.userAttention.key) .setContentTitle(app.getString(R.string.notification_user_action_required_title)) .setContentText(text) .setSmallIcon(R.drawable.ic_error_outline) @@ -84,70 +69,56 @@ class UserActionManager(val app: App) { manager.notify(System.currentTimeMillis().toInt(), notification) } + class UserActionCallback( + val onSuccess: ((data: Bundle) -> Unit)? = null, + val onFailure: (() -> Unit)? = null, + val onCancel: (() -> Unit)? = null, + ) + fun execute( - activity: AppCompatActivity, - profileId: Int?, - type: Int, - params: Bundle? = null, - onSuccess: ((params: Bundle) -> Unit)? = null, - onFailure: (() -> Unit)? = null + activity: AppCompatActivity, + event: UserActionRequiredEvent, + callback: UserActionCallback, ) { - d(TAG, "Running user action ($type) with params: ${params?.toJsonObject()}") - val isSuccessful = when (type) { - UserActionRequiredEvent.CAPTCHA_LIBRUS -> executeLibrus(activity, profileId, params, onSuccess, onFailure) - UserActionRequiredEvent.OAUTH_USOS -> executeOauth(activity, profileId, params, onSuccess, onFailure) - else -> false - } - if (!isSuccessful) { - onFailure?.invoke() + d(TAG, "Running user action (${event.type}) with params: ${event.params}") + val isSuccessful = when (event.type) { + UserActionRequiredEvent.Type.RECAPTCHA -> executeRecaptcha(activity, event, callback) + UserActionRequiredEvent.Type.OAUTH -> executeOauth(activity, event, callback) } + if (!isSuccessful) + callback.onFailure?.invoke() } - private fun executeLibrus( + private fun executeRecaptcha( activity: AppCompatActivity, - profileId: Int?, - params: Bundle?, - onSuccess: ((params: Bundle) -> Unit)?, - onFailure: (() -> Unit)?, + event: UserActionRequiredEvent, + callback: UserActionCallback, ): Boolean { - if (profileId == null) - return false - val extras = params?.getBundle("extras") - // show captcha dialog - // use passed onSuccess listener, else sync profile - LibrusCaptchaDialog( + val siteKey = event.params.getString("siteKey") ?: return false + val referer = event.params.getString("referer") ?: return false + RecaptchaPromptDialog( activity = activity, + siteKey = siteKey, + referer = referer, onSuccess = { code -> - val args = Bundle( + finishAction(activity, event, callback, Bundle( "recaptchaCode" to code, "recaptchaTime" to System.currentTimeMillis(), - ) - if (extras != null) - args.putAll(extras) - - if (onSuccess != null) - onSuccess(args) - else - EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) + )) }, - onFailure = onFailure, + onCancel = callback.onCancel, ).show() return true } private fun executeOauth( activity: AppCompatActivity, - profileId: Int?, - params: Bundle?, - onSuccess: ((params: Bundle) -> Unit)?, - onFailure: (() -> Unit)?, + event: UserActionRequiredEvent, + callback: UserActionCallback, ): Boolean { - if (profileId == null || params == null) - return false - val extras = params.getBundle("extras") - val storeKey = params.getString("responseStoreKey") ?: return false - params.getString("authorizeUrl") ?: return false - params.getString("redirectUrl") ?: return false + val storeKey = event.params.getString("responseStoreKey") ?: return false + event.params.getString("authorizeUrl") ?: return false + event.params.getString("redirectUrl") ?: return false var listener: Any? = null listener = object { @@ -155,26 +126,41 @@ class UserActionManager(val app: App) { fun onOAuthLoginResult(result: OAuthLoginResult) { EventBus.getDefault().unregister(listener) when { - result.isError -> onFailure?.invoke() + result.isError -> callback.onFailure?.invoke() result.responseUrl != null -> { - val args = Bundle( + finishAction(activity, event, callback, Bundle( storeKey to result.responseUrl, - ) - if (extras != null) - args.putAll(extras) - - if (onSuccess != null) - onSuccess(args) - else - EdziennikTask.syncProfile(profileId, arguments = args.toJsonObject()).enqueue(activity) + )) } + else -> callback.onCancel?.invoke() } } } EventBus.getDefault().register(listener) - val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(params) + val intent = Intent(activity, OAuthLoginActivity::class.java).putExtras(event.params) activity.startActivity(intent) return true } + + private fun finishAction( + activity: AppCompatActivity, + event: UserActionRequiredEvent, + callback: UserActionCallback, + data: Bundle, + ) { + val extras = event.params.getBundle("extras") + if (extras != null) + data.putAll(extras) + + if (callback.onSuccess != null) + callback.onSuccess.invoke(data) + else if (event.profileId != null) + EdziennikTask.syncProfile( + profileId = event.profileId, + arguments = data.toJsonObject(), + ).enqueue(activity) + else + callback.onFailure?.invoke() + } } diff --git a/app/src/main/res/layout/card_home_debug.xml b/app/src/main/res/layout/card_home_debug.xml index 18d21c02..4bcca808 100644 --- a/app/src/main/res/layout/card_home_debug.xml +++ b/app/src/main/res/layout/card_home_debug.xml @@ -25,13 +25,6 @@ android:layout_height="wrap_content" android:text="Save Debug Logs" /> - - ERROR_NOT_IMPLEMENTED ERROR_FILE_DOWNLOAD - ERROR_NO_STUDENTS_IN_ACCOUNT - - ERROR_CAPTCHA_NEEDED - ERROR_CAPTCHA_LIBRUS_PORTAL - ERROR_API_PDO_ERROR ERROR_API_INVALID_CLIENT ERROR_API_INVALID_ARGUMENT @@ -174,8 +169,6 @@ ERROR_PODLASIE_API_OTHER ERROR_PODLASIE_API_DATA_MISSING - ERROR_USOS_OAUTH_LOGIN_REQUEST - ERROR_TEMPLATE_WEB_OTHER EXCEPTION_API_TASK @@ -223,11 +216,6 @@ Nie zaimplementowano Wystąpił błąd podczas pobierania pliku. Dziennik może być przeciążony lub mieć przerwę techniczną. - Brak uczniów przypisanych do konta - - Wymagane rozwiązanie zadania Captcha - LIBRUS®️: wymagane rozwiązanie zadania Captcha - ERROR_API_PDO_ERROR Nieprawidłowy ID klienta API API: nieprawidłowy argument @@ -366,8 +354,6 @@ ERROR_PODLASIE_API_OTHER Brak danych. Zgłoś błąd programiście. - Wymagane logowanie w przeglądarce - ERROR_TEMPLATE_WEB_OTHER Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd. From 8097e8d06dc6a565e597b63a40e3998e346c51dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 16 Oct 2022 00:09:51 +0200 Subject: [PATCH 11/53] [API/Usos] Add syncing Courses and Terms. --- .../edziennik/data/api/Errors.kt | 1 + .../data/api/edziennik/usos/DataUsos.kt | 13 +-- .../edziennik/data/api/edziennik/usos/Usos.kt | 5 +- .../data/api/edziennik/usos/UsosFeatures.kt | 15 +++- .../data/api/edziennik/usos/data/UsosApi.kt | 24 ++++-- .../data/api/edziennik/usos/data/UsosData.kt | 14 ++- .../edziennik/usos/data/api/UsosApiCourses.kt | 86 +++++++++++++++++++ .../edziennik/usos/data/api/UsosApiTerms.kt | 65 ++++++++++++++ .../usos/firstlogin/UsosFirstLogin.kt | 2 +- .../edziennik/data/db/entity/Profile.kt | 4 + 10 files changed, 205 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index b4e892e6..8be89c6e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -203,6 +203,7 @@ const val ERROR_PODLASIE_API_DATA_MISSING = 632 const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702 const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703 const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704 +const val ERROR_USOS_API_INCOMPLETE_RESPONSE = 705 const val ERROR_TEMPLATE_WEB_OTHER = 801 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt index 0fd1b2ba..5cd054f8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -25,7 +25,7 @@ class DataUsos( } } - override fun generateUserCode() = "$schoolId:${studentNumber ?: studentId}" + override fun generateUserCode() = "$schoolId:${profile?.studentNumber ?: studentId}" var schoolId: String? get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId } @@ -67,13 +67,8 @@ class DataUsos( set(value) { loginStore.putLoginData("oauthTokenIsUser", value); mOauthTokenIsUser = value } private var mOauthTokenIsUser: Boolean? = null - var studentId: String? - get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId } + var studentId: Int + get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 } set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } - private var mStudentId: String? = null - - var studentNumber: String? - get() { mStudentNumber = mStudentNumber ?: profile?.getStudentData("studentNumber", null); return mStudentNumber } - set(value) { profile?.putStudentData("studentNumber", value) ?: return; mStudentNumber = value } - private var mStudentNumber: String? = null + private var mStudentId: Int? = null } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt index d676d006..cbf92ca8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt @@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosData import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent @@ -58,9 +59,9 @@ class Usos( d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}") d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") UsosLogin(data) { - /*UsosData(data) { + UsosData(data) { completed() - }*/ + } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt index a4ee1389..bdcf9c78 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt @@ -4,15 +4,26 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos +import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.data.api.FEATURE_ALWAYS_NEEDED import pl.szczodrzynski.edziennik.data.api.FEATURE_STUDENT_INFO -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS +import pl.szczodrzynski.edziennik.data.api.FEATURE_TEAM_INFO import pl.szczodrzynski.edziennik.data.api.models.Feature const val ENDPOINT_USOS_API_USER = 7000 +const val ENDPOINT_USOS_API_TERMS = 7010 +const val ENDPOINT_USOS_API_COURSES = 7020 val UsosFeatures = listOf( Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf( ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API, ), listOf(LOGIN_METHOD_USOS_API)), + + Feature(LOGIN_TYPE_USOS, FEATURE_SCHOOL_INFO, listOf( + ENDPOINT_USOS_API_TERMS to LOGIN_METHOD_USOS_API, + ), listOf(LOGIN_METHOD_USOS_API)), + + Feature(LOGIN_TYPE_USOS, FEATURE_TEAM_INFO, listOf( + ENDPOINT_USOS_API_COURSES to LOGIN_METHOD_USOS_API, + ), listOf(LOGIN_METHOD_USOS_API)), ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt index 1d3ab69c..829fefa4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data import com.google.gson.JsonArray import com.google.gson.JsonObject -import im.wangchao.mhttp.AbsCallbackHandler import im.wangchao.mhttp.Request import im.wangchao.mhttp.Response import im.wangchao.mhttp.body.MediaTypeUtils @@ -17,10 +16,7 @@ import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE import pl.szczodrzynski.edziennik.data.api.SERVER_USER_AGENT import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.models.ApiError -import pl.szczodrzynski.edziennik.ext.currentTimeUnix -import pl.szczodrzynski.edziennik.ext.hmacSHA1 -import pl.szczodrzynski.edziennik.ext.toQueryString -import pl.szczodrzynski.edziennik.ext.urlEncode +import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d import java.net.HttpURLConnection.* import java.util.UUID @@ -42,6 +38,9 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { val profile get() = data.profile + protected fun JsonObject.getLangString(key: String) = + this.getJsonObject(key)?.getString("pl") + private fun valueToString(value: Any) = when (value) { is String -> value is Number -> value.toString() @@ -74,15 +73,22 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { fun apiRequest( tag: String, service: String, - params: Map, + params: Map? = null, + fields: List? = null, responseType: ResponseType, onSuccess: (data: T, response: Response?) -> Unit, ) { val url = "${data.instanceUrl}services/$service" d(tag, "Request: Usos/Api - $url") - val formData = params.mapValues { - valueToString(it.value) - } + + val formData = mutableMapOf() + if (params != null) + formData.putAll(params.mapValues { + valueToString(it.value) + }) + if (fields != null) + formData["fields"] = valueToString(fields) + val auth = mutableMapOf( "realm" to url, "oauth_consumer_key" to (data.oauthConsumerKey ?: ""), diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt index 5ad199ff..5ea6ab66 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt @@ -7,7 +7,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web.TemplateWebSample import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_COURSES +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_USER +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiCourses +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTerms import pl.szczodrzynski.edziennik.utils.Utils.d class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { @@ -39,9 +43,17 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) { d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync") when (endpointId) { - ENDPOINT_USOS_API_USER -> { + /*ENDPOINT_USOS_API_USER -> { data.startProgress(R.string.edziennik_progress_endpoint_student_info) // TemplateWebSample(data, lastSync, onSuccess) + }*/ + ENDPOINT_USOS_API_TERMS -> { + data.startProgress(R.string.edziennik_progress_endpoint_school_info) + UsosApiTerms(data, lastSync, onSuccess) + } + ENDPOINT_USOS_API_COURSES -> { + data.startProgress(R.string.edziennik_progress_endpoint_teams) + UsosApiCourses(data, lastSync, onSuccess) } else -> onSuccess(endpointId) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt new file mode 100644 index 00000000..8f7359b5 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-15. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api + +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_COURSES +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi +import pl.szczodrzynski.edziennik.data.db.entity.Team +import pl.szczodrzynski.edziennik.ext.* + +class UsosApiCourses( + override val data: DataUsos, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit, +) : UsosApi(data, lastSync) { + companion object { + const val TAG = "UsosApiCourses" + } + + init { + apiRequest( + tag = TAG, + service = "courses/user", + fields = listOf( + // "terms" to listOf("id", "name", "start_date", "end_date"), + "course_editions" to listOf( + "course_id", + // "course_name", + // "term_id", + "user_groups" to listOf( + "course_unit_id", + "group_number", + "class_type", + "class_type_id", + // "lecturers", + ), + ), + ), + responseType = ResponseType.OBJECT, + ) { json, response -> + if (!processResponse(json)) { + data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response) + return@apiRequest + } + + data.setSyncNext(ENDPOINT_USOS_API_COURSES, 2 * DAY) + onSuccess(ENDPOINT_USOS_API_COURSES) + } + } + + private fun processResponse(json: JsonObject): Boolean { + // val term = json.getJsonArray("terms")?.firstOrNull() ?: return false + val courseEditions = json.getJsonObject("course_editions") + ?.entrySet() + ?.flatMap { it.value.asJsonArray } + ?.map { it.asJsonObject } ?: return false + + var hasValidTeam = false + for (courseEdition in courseEditions) { + val courseId = courseEdition.getString("course_id") ?: continue + // val courseName = courseEdition.getLangString("course_name") ?: continue + val userGroups = courseEdition.getJsonArray("user_groups")?.asJsonObjectList() ?: continue + for (userGroup in userGroups) { + val courseUnitId = userGroup.getLong("course_unit_id") ?: continue + val groupNumber = userGroup.getInt("group_number") ?: continue + val classType = userGroup.getLangString("class_type") ?: continue + val classTypeId = userGroup.getString("class_type_id") ?: continue + + data.teamList.put(courseUnitId, Team( + profileId, + courseUnitId, + "$classType $groupNumber ($courseId)", + 2, + "${data.schoolId}:${courseId} $classTypeId$groupNumber", + -1, + )) + hasValidTeam = true + } + } + return hasValidTeam + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt new file mode 100644 index 00000000..4a17bffa --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-15. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi +import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.utils.models.Date + +class UsosApiTerms( + override val data: DataUsos, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit, +) : UsosApi(data, lastSync) { + companion object { + const val TAG = "UsosApiTerms" + } + + init { + apiRequest( + tag = TAG, + service = "terms/search", + params = mapOf( + "query" to Date.getToday().year.toString(), + ), + responseType = ResponseType.ARRAY, + ) { json, response -> + if (!processResponse(json)) { + data.error(UsosApiCourses.TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response) + return@apiRequest + } + + data.setSyncNext(ENDPOINT_USOS_API_TERMS, 7 * DAY) + onSuccess(ENDPOINT_USOS_API_TERMS) + } + } + + private fun processResponse(json: JsonArray): Boolean { + val dates = mutableSetOf() + for (term in json.asJsonObjectList()) { + if (!term.getBoolean("is_active", false)) + continue + val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) } + val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) } + if (startDate != null) + dates += startDate + if (finishDate != null) + dates += finishDate + } + val datesSorted = dates.sorted() + if (datesSorted.size != 3) + return false + profile?.studentSchoolYearStart = datesSorted[0].year + profile?.dateSemester1Start = datesSorted[0] + profile?.dateSemester2Start = datesSorted[1] + profile?.dateYearEnd = datesSorted[2] + return true + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt index ad51cf92..4cb38cc6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt @@ -68,9 +68,9 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { accountName = null, // student account studentData = JsonObject( "studentId" to json.getInt("id"), - "studentNumber" to json.getInt("student_number"), ), ).also { + it.studentNumber = json.getInt("student_number", -1) it.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id") } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt index 9fc0521a..b1615fbc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt @@ -233,6 +233,10 @@ open class Profile( MainActivity.DRAWER_ITEM_GRADES, MainActivity.DRAWER_ITEM_HOMEWORK ) + LOGIN_TYPE_USOS -> listOf( + MainActivity.DRAWER_ITEM_TIMETABLE, + MainActivity.DRAWER_ITEM_AGENDA + ) else -> listOf( MainActivity.DRAWER_ITEM_TIMETABLE, MainActivity.DRAWER_ITEM_AGENDA, From e2fd714070d21086faf692b49a79f3e7798f8fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 16 Oct 2022 12:47:54 +0200 Subject: [PATCH 12/53] [UI/Timetable] Show subject-based lesson colors. (#141) * [UI/Timetable] Add timetable config dialog and implement UI options. * [UI/Timetable] Fix reloading timetable after changing config. * [UI/Timetable] Fix calculating lesson range boundaries. * [UI/Timetable] Add coloring subject names. --- .../edziennik/config/ProfileConfigUI.kt | 5 +++ .../ui/timetable/TimetableDayFragment.kt | 31 ++++++++++++++-- .../szczodrzynski/edziennik/utils/Colors.java | 35 +++++++++++++++++++ .../res/layout/timetable_config_dialog.xml | 8 +++++ app/src/main/res/layout/timetable_lesson.xml | 5 +-- app/src/main/res/values/strings.xml | 1 + 6 files changed, 80 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt index 743872b0..a3fb184e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt @@ -84,4 +84,9 @@ class ProfileConfigUI(private val config: ProfileConfig) { var timetableTrimHourRange: Boolean get() { mTimetableTrimHourRange = mTimetableTrimHourRange ?: config.values.get("timetableTrimHourRange", false); return mTimetableTrimHourRange ?: false } set(value) { config.set("timetableTrimHourRange", value); mTimetableTrimHourRange = value } + + private var mTimetableColorSubjectName: Boolean? = null + var timetableColorSubjectName: Boolean + get() { mTimetableColorSubjectName = mTimetableColorSubjectName ?: config.values.get("timetableColorSubjectName", false); return mTimetableColorSubjectName ?: false } + set(value) { config.set("timetableColorSubjectName", value); mTimetableColorSubjectName = value } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt index a2d99247..37e82a27 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt @@ -4,6 +4,7 @@ package pl.szczodrzynski.edziennik.ui.timetable +import android.graphics.drawable.ColorDrawable import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -12,6 +13,7 @@ import android.widget.FrameLayout import android.widget.LinearLayout import android.widget.TextView import androidx.asynclayoutinflater.view.AsyncLayoutInflater +import androidx.core.graphics.ColorUtils import androidx.core.view.* import com.linkedin.android.tachyon.DayView import com.linkedin.android.tachyon.DayViewConfig @@ -33,6 +35,7 @@ import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_END_HOUR import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_START_HOUR +import pl.szczodrzynski.edziennik.utils.Colors import pl.szczodrzynski.edziennik.utils.managers.NoteManager import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -309,13 +312,36 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { lesson.classroom?.let { add(it) } }.concat(arrowRight) + lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation) - lb.lessonNumber = lesson.displayLessonNumber val lessonText = lesson.getNoteSubstituteText(showNotes = true) ?: lesson.displaySubjectName + + val (subjectTextPrimary, subjectTextSecondary) = if (profileConfig.timetableColorSubjectName) { + val subjectColor = Colors.stringToMaterialColorCRC(lessonText?.toString() ?: "") + if (lb.annotationVisible) { + lb.subjectContainer.background = ColorDrawable(subjectColor) + } else { + lb.subjectContainer.setBackgroundResource(R.drawable.timetable_subject_color_rounded) + lb.subjectContainer.background.setTintColor(subjectColor) + } + when (ColorUtils.calculateLuminance(subjectColor) > 0.5) { + true -> /* light */ 0xFF000000 to 0xFF666666 + false -> /* dark */ 0xFFFFFFFF to 0xFFAAAAAA + } + } else { + lb.subjectContainer.background = null + null to colorSecondary + } + + lb.lessonNumber = lesson.displayLessonNumber + if (subjectTextPrimary != null) + lb.lessonNumberText.setTextColor(subjectTextPrimary.toInt()) lb.subjectName.text = lessonText?.let { if (lesson.type == Lesson.TYPE_CANCELLED || lesson.type == Lesson.TYPE_SHIFTED_SOURCE) - it.asStrikethroughSpannable().asColoredSpannable(colorSecondary) + it.asStrikethroughSpannable().asColoredSpannable(subjectTextSecondary.toInt()) + else if (subjectTextPrimary != null) + it.asColoredSpannable(subjectTextPrimary.toInt()) else it } @@ -342,7 +368,6 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { } //lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD) - lb.annotationVisible = manager.getAnnotation(activity, lesson, lb.annotation) val lessonNumberMargin = if (lb.annotationVisible) (-8).dp else 0 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java index 1f6c7ad3..39371516 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java @@ -15,6 +15,7 @@ import androidx.core.graphics.ColorUtils; import java.security.MessageDigest; import java.util.Arrays; import java.util.Random; +import java.util.zip.CRC32; import pl.szczodrzynski.edziennik.data.db.entity.Grade; @@ -84,6 +85,28 @@ public class Colors { 0xFF6D4C41 }; + public static final int[] materialColorsBasic = { + 0xFFE53935, 0xFFD81B60, 0xFF8E24AA, 0xFF5E35B1, + 0xFF3949AB, 0xFF1E88E5, 0xFF039BE5, 0xFF00ACC1, + 0xFF00897B, 0xFF43A047, 0xFF7CB342, 0xFFC0CA33, + 0xFFFDD835, 0xFFFFB300, 0xFFFB8C00, 0xFFF4511E, + 0xFF6D4C41, 0xFF757575, 0xFF546E7A, 0xFF00E676, + + 0xFFEF9A9A, 0xFFF48FB1, 0xFFCE93D8, 0xFFB39DDB, + 0xFF9FA8DA, 0xFF90CAF9, 0xFF81D4FA, 0xFF80DEEA, + 0xFF80CBC4, 0xFFA5D6A7, 0xFFC5E1A5, 0xFFE6EE9C, + 0xFFFFF59D, 0xFFFFE082, 0xFFFFCC80, 0xFFFFAB91, + 0xFFBCAAA4, 0xFFEEEEEE, 0xFFB0BEC5, 0xFFCCFF90, + }; + + public static final int[] metroColors = { + 0xFF76FF03, 0xFF60A917, 0xFF00C853, 0xFF00ABA9, + 0xFF1BA1E2, 0xFF0050EF, 0xFF6A00FF, 0xFFAA00FF, + 0xFFF472D0, 0xFFD80073, 0xFFA20025, 0xFFE51400, + 0xFFFA6800, 0xFFF0A30A, 0xFFE3C800, 0xFF795548, + 0xFF6D8764, 0xFF647687, 0xFF76608A, 0xFFA0522D, + }; + /** * Used for teacher's images (e.g. in messages or announcements). * @param s teacher's fullName @@ -115,6 +138,18 @@ public class Colors { return materialColors[getRandomNumberInRange(0, materialColors.length-1, seed)]; } + public static int stringToMaterialColorCRC(String s) { + long seed; + try { + CRC32 crc = new CRC32(); + crc.update(s.getBytes()); + seed = crc.getValue(); + } catch (Exception e) { + seed = 1234; + } + return metroColors[(int) (seed % metroColors.length)]; + } + public static int gradeToColor(Grade grade) { if (grade.getType() == Grade.TYPE_POINT_SUM) { diff --git a/app/src/main/res/layout/timetable_config_dialog.xml b/app/src/main/res/layout/timetable_config_dialog.xml index b248e793..19e165cf 100644 --- a/app/src/main/res/layout/timetable_config_dialog.xml +++ b/app/src/main/res/layout/timetable_config_dialog.xml @@ -44,6 +44,14 @@ android:minHeight="32dp" android:text="@string/timetable_config_show_attendance" /> + + - + android:paddingVertical="4dp" + tools:background="@drawable/timetable_subject_color_rounded"> Ustawienia planu lekcji Pokazuj wydarzenia przy lekcjach Pokazuj rodzaj obecności na lekcji + Koloruj nazwę przedmiotu Nie pokazuj godzin bez lekcji From 4de066bf5facab8e303dedb747fc6cb8c391f3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 16 Oct 2022 17:21:36 +0200 Subject: [PATCH 13/53] [API/Usos] Implement Timetable. --- .../data/api/edziennik/usos/UsosFeatures.kt | 24 +++- .../data/api/edziennik/usos/data/UsosData.kt | 10 +- .../edziennik/usos/data/api/UsosApiCourses.kt | 10 +- .../edziennik/usos/data/api/UsosApiTerms.kt | 3 +- .../usos/data/api/UsosApiTimetable.kt | 132 ++++++++++++++++++ .../edziennik/ext/TimeExtensions.kt | 11 +- .../ui/timetable/TimetableDayFragment.kt | 25 ++-- 7 files changed, 188 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt index bdcf9c78..50c15582 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt @@ -5,25 +5,35 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos import pl.szczodrzynski.edziennik.data.api.* -import pl.szczodrzynski.edziennik.data.api.FEATURE_ALWAYS_NEEDED -import pl.szczodrzynski.edziennik.data.api.FEATURE_STUDENT_INFO -import pl.szczodrzynski.edziennik.data.api.FEATURE_TEAM_INFO import pl.szczodrzynski.edziennik.data.api.models.Feature -const val ENDPOINT_USOS_API_USER = 7000 -const val ENDPOINT_USOS_API_TERMS = 7010 -const val ENDPOINT_USOS_API_COURSES = 7020 +const val ENDPOINT_USOS_API_USER = 7000 +const val ENDPOINT_USOS_API_TERMS = 7010 +const val ENDPOINT_USOS_API_COURSES = 7020 +const val ENDPOINT_USOS_API_TIMETABLE = 7030 val UsosFeatures = listOf( + /* + * Student information + */ Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf( ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API, ), listOf(LOGIN_METHOD_USOS_API)), + /* + * Terms & courses + */ Feature(LOGIN_TYPE_USOS, FEATURE_SCHOOL_INFO, listOf( ENDPOINT_USOS_API_TERMS to LOGIN_METHOD_USOS_API, ), listOf(LOGIN_METHOD_USOS_API)), - Feature(LOGIN_TYPE_USOS, FEATURE_TEAM_INFO, listOf( ENDPOINT_USOS_API_COURSES to LOGIN_METHOD_USOS_API, ), listOf(LOGIN_METHOD_USOS_API)), + + /* + * Timetable + */ + Feature(LOGIN_TYPE_USOS, FEATURE_TIMETABLE, listOf( + ENDPOINT_USOS_API_TIMETABLE to LOGIN_METHOD_USOS_API, + ), listOf(LOGIN_METHOD_USOS_API)), ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt index 5ea6ab66..6f3b6039 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt @@ -6,12 +6,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web.TemplateWebSample -import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos -import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_COURSES -import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS -import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_USER +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.* import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiCourses import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTerms +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTimetable import pl.szczodrzynski.edziennik.utils.Utils.d class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { @@ -55,6 +53,10 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_teams) UsosApiCourses(data, lastSync, onSuccess) } + ENDPOINT_USOS_API_TIMETABLE -> { + data.startProgress(R.string.edziennik_progress_endpoint_timetable) + UsosApiTimetable(data, lastSync, onSuccess) + } else -> onSuccess(endpointId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt index 8f7359b5..613d9f08 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt @@ -29,12 +29,12 @@ class UsosApiCourses( // "terms" to listOf("id", "name", "start_date", "end_date"), "course_editions" to listOf( "course_id", - // "course_name", + "course_name", // "term_id", "user_groups" to listOf( "course_unit_id", "group_number", - "class_type", + // "class_type", "class_type_id", // "lecturers", ), @@ -62,18 +62,18 @@ class UsosApiCourses( var hasValidTeam = false for (courseEdition in courseEditions) { val courseId = courseEdition.getString("course_id") ?: continue - // val courseName = courseEdition.getLangString("course_name") ?: continue + val courseName = courseEdition.getLangString("course_name") ?: continue val userGroups = courseEdition.getJsonArray("user_groups")?.asJsonObjectList() ?: continue for (userGroup in userGroups) { val courseUnitId = userGroup.getLong("course_unit_id") ?: continue val groupNumber = userGroup.getInt("group_number") ?: continue - val classType = userGroup.getLangString("class_type") ?: continue + // val classType = userGroup.getLangString("class_type") ?: continue val classTypeId = userGroup.getString("class_type_id") ?: continue data.teamList.put(courseUnitId, Team( profileId, courseUnitId, - "$classType $groupNumber ($courseId)", + "${profile?.studentClassName} $classTypeId$groupNumber - $courseName", 2, "${data.schoolId}:${courseId} $classTypeId$groupNumber", -1, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt index 4a17bffa..1bf47288 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTerms.kt @@ -5,7 +5,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api import com.google.gson.JsonArray -import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS @@ -32,7 +31,7 @@ class UsosApiTerms( responseType = ResponseType.ARRAY, ) { json, response -> if (!processResponse(json)) { - data.error(UsosApiCourses.TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response) + data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response) return@apiRequest } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt new file mode 100644 index 00000000..355731a8 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt @@ -0,0 +1,132 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-16. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api + +import com.google.gson.JsonArray +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TIMETABLE +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi +import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel +import pl.szczodrzynski.edziennik.data.db.entity.Lesson +import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.utils.models.Date +import pl.szczodrzynski.edziennik.utils.models.Time +import pl.szczodrzynski.edziennik.utils.models.Week + +class UsosApiTimetable( + override val data: DataUsos, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit, +) : UsosApi(data, lastSync) { + companion object { + const val TAG = "UsosApiTimetable" + } + + init { + val currentWeekStart = Week.getWeekStart() + if (Date.getToday().weekDay > 4) + currentWeekStart.stepForward(0, 0, 7) + + val weekStart = data.arguments + ?.getString("weekStart") + ?.let { Date.fromY_m_d(it) } + ?: currentWeekStart + val weekEnd = weekStart.clone().stepForward(0, 0, 6) + + apiRequest( + tag = TAG, + service = "tt/user", + params = mapOf( + "start" to weekStart.stringY_m_d, + "days" to 7, + ), + fields = listOf( + "type", + "start_time", + "end_time", + "unit_id", + "course_id", + "course_name", + "lecturer_ids", + "building_id", + "room_number", + "classtype_id", + "group_number", + ), + responseType = ResponseType.ARRAY, + ) { json, response -> + if (!processResponse(json, weekStart..weekEnd)) { + data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response) + return@apiRequest + } + + data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd)) + data.setSyncNext(ENDPOINT_USOS_API_TIMETABLE, SYNC_ALWAYS) + onSuccess(ENDPOINT_USOS_API_TIMETABLE) + } + } + + private fun processResponse(json: JsonArray, syncRange: ClosedRange): Boolean { + val foundDates = mutableSetOf() + + for (activity in json.asJsonObjectList()) { + val type = activity.getString("type") + if (type !in listOf("classgroup", "classgroup2")) + continue + + val startTime = activity.getString("start_time") ?: continue + val endTime = activity.getString("end_time") ?: continue + val unitId = activity.getLong("unit_id", -1) + val courseName = activity.getLangString("course_name") ?: continue + val courseId = activity.getString("course_id") ?: continue + val lecturerIds = activity.getJsonArray("lecturer_ids")?.map { it.asLong } + val buildingId = activity.getString("building_id") + val roomNumber = activity.getString("room_number") + val classTypeId = activity.getString("classtype_id") + val groupNumber = activity.getString("group_number") + + val lesson = Lesson(profileId, -1).also { + it.type = Lesson.TYPE_NORMAL + it.date = Date.fromY_m_d(startTime) + it.startTime = Time.fromY_m_d_H_m_s(startTime) + it.endTime = Time.fromY_m_d_H_m_s(endTime) + it.subjectId = data.getSubject( + id = null, + name = courseName, + shortName = courseId, + ).id + it.teacherId = lecturerIds?.firstOrNull() ?: -1L + it.teamId = unitId + val groupName = classTypeId?.plus(groupNumber)?.let { s -> "($s)" } + it.classroom = "$buildingId / $roomNumber ${groupName ?: ""}" + it.id = it.buildId() + } + lesson.date?.let { foundDates += it } + + val seen = profile?.empty != false || lesson.date!! < Date.getToday() + data.lessonList.add(lesson) + if (lesson.type != Lesson.TYPE_NORMAL) + data.metadataList += Metadata( + profileId, + Metadata.TYPE_LESSON_CHANGE, + lesson.id, + seen, + seen, + ) + } + + val notFoundDates = syncRange.asSequence() - foundDates + for (date in notFoundDates) { + data.lessonList += Lesson(profileId, date.value.toLong()).also { + it.type = Lesson.TYPE_NO_LESSONS + it.date = date + } + } + return true + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TimeExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TimeExtensions.kt index 114a5a40..31bd952c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/TimeExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/TimeExtensions.kt @@ -7,9 +7,10 @@ package pl.szczodrzynski.edziennik.ext import android.content.Context import im.wangchao.mhttp.Response import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time import java.text.SimpleDateFormat -import java.util.* +import java.util.Locale const val MINUTE = 60L const val HOUR = 60L*MINUTE @@ -115,3 +116,11 @@ fun Context.getSyncInterval(interval: Int): String { "" return hoursText?.plus(" $minutesText") ?: minutesText } + +fun ClosedRange.asSequence(): Sequence = sequence { + val date = this@asSequence.start.clone() + while (date in this@asSequence) { + yield(date.clone()) + date.stepForward(0, 0, 1) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt index 37e82a27..1e4d9773 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt @@ -21,8 +21,11 @@ import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp import kotlinx.coroutines.* -import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull @@ -40,8 +43,8 @@ import pl.szczodrzynski.edziennik.utils.managers.NoteManager import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.mutableLazy -import java.util.* import kotlin.coroutines.CoroutineContext +import kotlin.math.max import kotlin.math.min class TimetableDayFragment : LazyFragment(), CoroutineScope { @@ -82,7 +85,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { startHour = startHour, endHour = endHour, dividerHeight = 1.dp, - halfHourHeight = 60.dp, + halfHourHeight = if (app.profile.loginStoreType == LOGIN_TYPE_USOS) 45.dp else 30.dp, hourDividerColor = R.attr.hourDividerColor.resolveAttr(context), halfHourDividerColor = R.attr.halfHourDividerColor.resolveAttr(context), hourLabelWidth = 40.dp, @@ -184,11 +187,18 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { val lessonsActual = lessons.filter { it.type != Lesson.TYPE_NO_LESSONS } + val minStartHour = lessonsActual.minOf { it.displayStartTime?.hour ?: DEFAULT_END_HOUR } + val maxEndHour = lessonsActual.maxOf { it.displayEndTime?.hour?.plus(1) ?: DEFAULT_START_HOUR } + if (profileConfig.timetableTrimHourRange) { dayViewDelegate.deinitialize() // end/start defaults are swapped on purpose - startHour = lessonsActual.minOf { it.displayStartTime?.hour ?: DEFAULT_END_HOUR } - endHour = lessonsActual.maxOf { it.displayEndTime?.hour?.plus(1) ?: DEFAULT_START_HOUR } + startHour = minStartHour + endHour = maxEndHour + } else if (startHour > minStartHour || endHour < maxEndHour) { + dayViewDelegate.deinitialize() + startHour = min(startHour, minStartHour) + endHour = max(endHour, maxEndHour) } b.scrollView.isVisible = true @@ -377,9 +387,8 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { // The day view needs the event time ranges in the start minute/end minute format, // so calculate those here - val startMinute = 60 * (lesson.displayStartTime?.hour - ?: 0) + (lesson.displayStartTime?.minute ?: 0) - val endMinute = startMinute + 45 + val startMinute = 60 * startTime.hour + startTime.minute + val endMinute = 60 * endTime.hour + endTime.minute eventTimeRanges.add(DayView.EventTimeRange(startMinute, endMinute)) } From 044cedff99a617a3a39fc54cc64e27e54b084735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 16 Oct 2022 18:13:22 +0200 Subject: [PATCH 14/53] [Usos] Override lesson colors by activity type. --- .../98.json | 2314 +++++++++++++++++ .../usos/data/api/UsosApiTimetable.kt | 9 + .../szczodrzynski/edziennik/data/db/AppDb.kt | 3 +- .../edziennik/data/db/entity/Lesson.kt | 2 + .../data/db/migration/Migration98.kt | 15 + .../ui/timetable/TimetableDayFragment.kt | 2 +- 6 files changed, 2343 insertions(+), 2 deletions(-) create mode 100644 app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration98.kt diff --git a/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json new file mode 100644 index 00000000..1a291aef --- /dev/null +++ b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json @@ -0,0 +1,2314 @@ +{ + "formatVersion": 1, + "database": { + "version": 98, + "identityHash": "2612ebba9802eedc7ebc69724606a23c", + "entities": [ + { + "tableName": "grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `gradeId` INTEGER NOT NULL, `gradeName` TEXT NOT NULL, `gradeType` INTEGER NOT NULL, `gradeValue` REAL NOT NULL, `gradeWeight` REAL NOT NULL, `gradeColor` INTEGER NOT NULL, `gradeCategory` TEXT, `gradeDescription` TEXT, `gradeComment` TEXT, `gradeSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `gradeValueMax` REAL, `gradeClassAverage` REAL, `gradeParentId` INTEGER, `gradeIsImprovement` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `gradeId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "gradeId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "gradeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "gradeType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "gradeValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "gradeWeight", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "gradeColor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "gradeCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "gradeDescription", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "comment", + "columnName": "gradeComment", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "semester", + "columnName": "gradeSemester", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "valueMax", + "columnName": "gradeValueMax", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "classAverage", + "columnName": "gradeClassAverage", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "parentId", + "columnName": "gradeParentId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isImprovement", + "columnName": "gradeIsImprovement", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "gradeId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_grades_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_grades_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `teacherLoginId` TEXT, `teacherName` TEXT, `teacherSurname` TEXT, `teacherType` INTEGER NOT NULL, `teacherTypeDescription` TEXT, `teacherSubjects` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "teacherLoginId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "teacherName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "surname", + "columnName": "teacherSurname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "teacherType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "typeDescription", + "columnName": "teacherTypeDescription", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subjects", + "columnName": "teacherSubjects", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teacherId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "teacherAbsence", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceId` INTEGER NOT NULL, `teacherAbsenceType` INTEGER NOT NULL, `teacherAbsenceName` TEXT, `teacherAbsenceDateFrom` TEXT NOT NULL, `teacherAbsenceDateTo` TEXT NOT NULL, `teacherAbsenceTimeFrom` TEXT, `teacherAbsenceTimeTo` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teacherAbsenceId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "teacherAbsenceType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "teacherAbsenceName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateFrom", + "columnName": "teacherAbsenceDateFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateTo", + "columnName": "teacherAbsenceDateTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timeFrom", + "columnName": "teacherAbsenceTimeFrom", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timeTo", + "columnName": "teacherAbsenceTimeTo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teacherAbsenceId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_teacherAbsence_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teacherAbsence_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "teacherAbsenceTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceTypeId` INTEGER NOT NULL, `teacherAbsenceTypeName` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceTypeId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teacherAbsenceTypeId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "teacherAbsenceTypeName", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teacherAbsenceTypeId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `subjectLongName` TEXT, `subjectShortName` TEXT, `subjectColor` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `subjectId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "longName", + "columnName": "subjectLongName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shortName", + "columnName": "subjectShortName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "subjectColor", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "subjectId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "notices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noticeId` INTEGER NOT NULL, `noticeType` INTEGER NOT NULL, `noticeSemester` INTEGER NOT NULL, `noticeText` TEXT NOT NULL, `noticeCategory` TEXT, `noticePoints` REAL, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `noticeId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "noticeId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "noticeType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "noticeSemester", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "noticeText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "noticeCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "points", + "columnName": "noticePoints", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "noticeId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_notices_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_notices_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "teams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `teamType` INTEGER NOT NULL, `teamName` TEXT, `teamCode` TEXT, `teamTeacherId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teamId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "teamType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "teamName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "code", + "columnName": "teamCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teamTeacherId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teamId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendances", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `attendanceId` INTEGER NOT NULL, `attendanceBaseType` INTEGER NOT NULL, `attendanceTypeName` TEXT NOT NULL, `attendanceTypeShort` TEXT NOT NULL, `attendanceTypeSymbol` TEXT NOT NULL, `attendanceTypeColor` INTEGER, `attendanceDate` TEXT NOT NULL, `attendanceTime` TEXT, `attendanceSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `attendanceLessonTopic` TEXT, `attendanceLessonNumber` INTEGER, `attendanceIsCounted` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `attendanceId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "attendanceId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "baseType", + "columnName": "attendanceBaseType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "typeName", + "columnName": "attendanceTypeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeShort", + "columnName": "attendanceTypeShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeSymbol", + "columnName": "attendanceTypeSymbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeColor", + "columnName": "attendanceTypeColor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "date", + "columnName": "attendanceDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "attendanceTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "semester", + "columnName": "attendanceSemester", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lessonTopic", + "columnName": "attendanceLessonTopic", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lessonNumber", + "columnName": "attendanceLessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isCounted", + "columnName": "attendanceIsCounted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "attendanceId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_attendances_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_attendances_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "events", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventId` INTEGER NOT NULL, `eventDate` TEXT NOT NULL, `eventTime` TEXT, `eventTopic` TEXT NOT NULL, `eventColor` INTEGER, `eventType` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `eventAddedManually` INTEGER NOT NULL, `eventSharedBy` TEXT, `eventSharedByName` TEXT, `eventBlacklisted` INTEGER NOT NULL, `eventIsDone` INTEGER NOT NULL, `eventIsDownloaded` INTEGER NOT NULL, `homeworkBody` TEXT, `attachmentIds` TEXT, `attachmentNames` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "eventId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "eventDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "eventTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "topic", + "columnName": "eventTopic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "eventColor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "eventType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedManually", + "columnName": "eventAddedManually", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sharedBy", + "columnName": "eventSharedBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedByName", + "columnName": "eventSharedByName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "blacklisted", + "columnName": "eventBlacklisted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDone", + "columnName": "eventIsDone", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDownloaded", + "columnName": "eventIsDownloaded", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "homeworkBody", + "columnName": "homeworkBody", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentIds", + "columnName": "attachmentIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentNames", + "columnName": "attachmentNames", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "eventId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_events_profileId_eventDate_eventTime", + "unique": false, + "columnNames": [ + "profileId", + "eventDate", + "eventTime" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventDate_eventTime` ON `${TABLE_NAME}` (`profileId`, `eventDate`, `eventTime`)" + }, + { + "name": "index_events_profileId_eventType", + "unique": false, + "columnNames": [ + "profileId", + "eventType" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventType` ON `${TABLE_NAME}` (`profileId`, `eventType`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "eventTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventType` INTEGER NOT NULL, `eventTypeName` TEXT NOT NULL, `eventTypeColor` INTEGER NOT NULL, `eventTypeOrder` INTEGER NOT NULL, `eventTypeSource` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventType`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "eventType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "eventTypeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "eventTypeColor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "eventTypeOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "eventTypeSource", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "eventType" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "loginStores", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `loginStoreMode` INTEGER NOT NULL, `loginStoreData` TEXT NOT NULL, PRIMARY KEY(`loginStoreId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "loginStoreId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "loginStoreType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mode", + "columnName": "loginStoreMode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "loginStoreData", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "loginStoreId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "profiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `name` TEXT NOT NULL, `subname` TEXT, `studentNameLong` TEXT NOT NULL, `studentNameShort` TEXT NOT NULL, `accountName` TEXT, `studentData` TEXT NOT NULL, `image` TEXT, `empty` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `archiveId` INTEGER, `syncEnabled` INTEGER NOT NULL, `enableSharedEvents` INTEGER NOT NULL, `registration` INTEGER NOT NULL, `userCode` TEXT NOT NULL, `studentNumber` INTEGER NOT NULL, `studentClassName` TEXT, `studentSchoolYearStart` INTEGER NOT NULL, `dateSemester1Start` TEXT NOT NULL, `dateSemester2Start` TEXT NOT NULL, `dateYearEnd` TEXT NOT NULL, `disabledNotifications` TEXT, `lastReceiversSync` INTEGER NOT NULL, PRIMARY KEY(`profileId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "loginStoreId", + "columnName": "loginStoreId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "loginStoreType", + "columnName": "loginStoreType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subname", + "columnName": "subname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentNameLong", + "columnName": "studentNameLong", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentNameShort", + "columnName": "studentNameShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentData", + "columnName": "studentData", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "empty", + "columnName": "empty", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "archived", + "columnName": "archived", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "archiveId", + "columnName": "archiveId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "syncEnabled", + "columnName": "syncEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enableSharedEvents", + "columnName": "enableSharedEvents", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registration", + "columnName": "registration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userCode", + "columnName": "userCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentNumber", + "columnName": "studentNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentClassName", + "columnName": "studentClassName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentSchoolYearStart", + "columnName": "studentSchoolYearStart", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateSemester1Start", + "columnName": "dateSemester1Start", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateSemester2Start", + "columnName": "dateSemester2Start", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateYearEnd", + "columnName": "dateYearEnd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "disabledNotifications", + "columnName": "disabledNotifications", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastReceiversSync", + "columnName": "lastReceiversSync", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "luckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `luckyNumberDate` INTEGER NOT NULL, `luckyNumber` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `luckyNumberDate`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "luckyNumberDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "luckyNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "luckyNumberDate" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "announcements", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `announcementId` INTEGER NOT NULL, `announcementSubject` TEXT NOT NULL, `announcementText` TEXT, `announcementStartDate` TEXT, `announcementEndDate` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `announcementIdString` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `announcementId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "announcementId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "announcementSubject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "announcementText", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "startDate", + "columnName": "announcementStartDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endDate", + "columnName": "announcementEndDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "idString", + "columnName": "announcementIdString", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "announcementId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_announcements_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_announcements_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "gradeCategories", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `categoryId` INTEGER NOT NULL, `weight` REAL NOT NULL, `color` INTEGER NOT NULL, `text` TEXT, `columns` TEXT, `valueFrom` REAL NOT NULL, `valueTo` REAL NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `categoryId`, `type`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categoryId", + "columnName": "categoryId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "columns", + "columnName": "columns", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "valueFrom", + "columnName": "valueFrom", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "valueTo", + "columnName": "valueTo", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "categoryId", + "type" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "feedbackMessages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `text` TEXT NOT NULL, `senderName` TEXT NOT NULL, `deviceId` TEXT, `deviceName` TEXT, `devId` INTEGER, `devImage` TEXT, `sentTime` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "received", + "columnName": "received", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "senderName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "deviceId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deviceName", + "columnName": "deviceName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "devId", + "columnName": "devId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "devImage", + "columnName": "devImage", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sentTime", + "columnName": "sentTime", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "messageId" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, `messageType` INTEGER NOT NULL, `messageSubject` TEXT NOT NULL, `messageBody` TEXT, `senderId` INTEGER, `addedDate` INTEGER NOT NULL, `messageIsPinned` INTEGER NOT NULL, `hasAttachments` INTEGER NOT NULL, `attachmentIds` TEXT, `attachmentNames` TEXT, `attachmentSizes` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "messageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "messageType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "messageSubject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "body", + "columnName": "messageBody", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "senderId", + "columnName": "senderId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isStarred", + "columnName": "messageIsPinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasAttachments", + "columnName": "hasAttachments", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attachmentIds", + "columnName": "attachmentIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentNames", + "columnName": "attachmentNames", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentSizes", + "columnName": "attachmentSizes", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "messageId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_messages_profileId_messageType", + "unique": false, + "columnNames": [ + "profileId", + "messageType" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_profileId_messageType` ON `${TABLE_NAME}` (`profileId`, `messageType`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "messageRecipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageRecipientId` INTEGER NOT NULL, `messageRecipientReplyId` INTEGER NOT NULL, `messageRecipientReadDate` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageRecipientId`, `messageId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "messageRecipientId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replyId", + "columnName": "messageRecipientReplyId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readDate", + "columnName": "messageRecipientReadDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "messageRecipientId", + "messageId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "debugLogs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "endpointTimers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `endpointId` INTEGER NOT NULL, `endpointLastSync` INTEGER, `endpointNextSync` INTEGER NOT NULL, `endpointViewId` INTEGER, PRIMARY KEY(`profileId`, `endpointId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endpointId", + "columnName": "endpointId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastSync", + "columnName": "endpointLastSync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nextSync", + "columnName": "endpointNextSync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewId", + "columnName": "endpointViewId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "endpointId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "lessonRanges", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonRangeNumber` INTEGER NOT NULL, `lessonRangeStart` TEXT NOT NULL, `lessonRangeEnd` TEXT NOT NULL, PRIMARY KEY(`profileId`, `lessonRangeNumber`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lessonNumber", + "columnName": "lessonRangeNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "lessonRangeStart", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "endTime", + "columnName": "lessonRangeEnd", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "lessonRangeNumber" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "notifications", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL, `textLong` TEXT, `type` INTEGER NOT NULL, `profileId` INTEGER, `profileName` TEXT, `posted` INTEGER NOT NULL, `viewId` INTEGER, `extras` TEXT, `addedDate` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "textLong", + "columnName": "textLong", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileName", + "columnName": "profileName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "posted", + "columnName": "posted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewId", + "columnName": "viewId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "extras", + "columnName": "extras", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "classrooms", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "noticeTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendanceTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `baseType` INTEGER NOT NULL, `typeName` TEXT NOT NULL, `typeShort` TEXT NOT NULL, `typeSymbol` TEXT NOT NULL, `typeColor` INTEGER, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "baseType", + "columnName": "baseType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "typeName", + "columnName": "typeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeShort", + "columnName": "typeShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeSymbol", + "columnName": "typeSymbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeColor", + "columnName": "typeColor", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `date` TEXT, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT, `oldDate` TEXT, `oldLessonNumber` INTEGER, `oldStartTime` TEXT, `oldEndTime` TEXT, `oldSubjectId` INTEGER, `oldTeacherId` INTEGER, `oldTeamId` INTEGER, `oldClassroom` TEXT, `isExtra` INTEGER NOT NULL, `color` INTEGER, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lessonNumber", + "columnName": "lessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "classroom", + "columnName": "classroom", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldDate", + "columnName": "oldDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldLessonNumber", + "columnName": "oldLessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldStartTime", + "columnName": "oldStartTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldEndTime", + "columnName": "oldEndTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldSubjectId", + "columnName": "oldSubjectId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldTeacherId", + "columnName": "oldTeacherId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldTeamId", + "columnName": "oldTeamId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldClassroom", + "columnName": "oldClassroom", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isExtra", + "columnName": "isExtra", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_timetable_profileId_type_date", + "unique": false, + "columnNames": [ + "profileId", + "type", + "date" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_date` ON `${TABLE_NAME}` (`profileId`, `type`, `date`)" + }, + { + "name": "index_timetable_profileId_type_oldDate", + "unique": false, + "columnNames": [ + "profileId", + "type", + "oldDate" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_oldDate` ON `${TABLE_NAME}` (`profileId`, `type`, `oldDate`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "config", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profileId`, `key`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "librusLessons", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER, PRIMARY KEY(`profileId`, `lessonId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lessonId", + "columnName": "lessonId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "lessonId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_librusLessons_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_librusLessons_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "timetableManual", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `repeatBy` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `weekDay` INTEGER, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT)", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repeatBy", + "columnName": "repeatBy", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "weekDay", + "columnName": "weekDay", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lessonNumber", + "columnName": "lessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "classroom", + "columnName": "classroom", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_timetableManual_profileId_date", + "unique": false, + "columnNames": [ + "profileId", + "date" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_date` ON `${TABLE_NAME}` (`profileId`, `date`)" + }, + { + "name": "index_timetableManual_profileId_weekDay", + "unique": false, + "columnNames": [ + "profileId", + "weekDay" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_weekDay` ON `${TABLE_NAME}` (`profileId`, `weekDay`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `noteOwnerType` TEXT, `noteOwnerId` INTEGER, `noteReplacesOriginal` INTEGER NOT NULL, `noteTopic` TEXT, `noteBody` TEXT NOT NULL, `noteColor` INTEGER, `noteSharedBy` TEXT, `noteSharedByName` TEXT, `addedDate` INTEGER NOT NULL, PRIMARY KEY(`noteId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "noteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ownerType", + "columnName": "noteOwnerType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ownerId", + "columnName": "noteOwnerId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "replacesOriginal", + "columnName": "noteReplacesOriginal", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "noteTopic", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "body", + "columnName": "noteBody", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "noteColor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharedBy", + "columnName": "noteSharedBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedByName", + "columnName": "noteSharedByName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "noteId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_notes_profileId_noteOwnerType_noteOwnerId", + "unique": false, + "columnNames": [ + "profileId", + "noteOwnerType", + "noteOwnerId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_notes_profileId_noteOwnerType_noteOwnerId` ON `${TABLE_NAME}` (`profileId`, `noteOwnerType`, `noteOwnerId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `metadataId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thingType` INTEGER NOT NULL, `thingId` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `notified` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "metadataId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "thingType", + "columnName": "thingType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "thingId", + "columnName": "thingId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "seen", + "columnName": "seen", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notified", + "columnName": "notified", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "metadataId" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_metadata_profileId_thingType_thingId", + "unique": true, + "columnNames": [ + "profileId", + "thingType", + "thingId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_metadata_profileId_thingType_thingId` ON `${TABLE_NAME}` (`profileId`, `thingType`, `thingId`)" + } + ], + "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, '2612ebba9802eedc7ebc69724606a23c')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt index 355731a8..6c1acc54 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt @@ -105,6 +105,15 @@ class UsosApiTimetable( val groupName = classTypeId?.plus(groupNumber)?.let { s -> "($s)" } it.classroom = "$buildingId / $roomNumber ${groupName ?: ""}" it.id = it.buildId() + + it.color = when (classTypeId) { + "WYK" -> 0xff0d6091 + "CW" -> 0xff54306e + "LAB" -> 0xff772747 + "KON" -> 0xff1e5128 + "^P?SEM" -> 0xff1e5128 // TODO make it regex + else -> 0xff08534c + }.toInt() } lesson.date?.let { foundDates += it } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt index 93758366..b7f6ccf2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt @@ -44,7 +44,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.* TimetableManual::class, Note::class, Metadata::class -], version = 97) +], version = 98) @TypeConverters( ConverterTime::class, ConverterDate::class, @@ -185,6 +185,7 @@ abstract class AppDb : RoomDatabase() { Migration95(), Migration96(), Migration97(), + Migration98(), ).allowMainThreadQueries().build() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Lesson.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Lesson.kt index 5123a2f5..37b7f6f3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Lesson.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Lesson.kt @@ -74,6 +74,8 @@ open class Lesson( @Ignore var showAsUnseen = false + var color: Int? = null + override fun toString(): String { return "Lesson(profileId=$profileId, " + "id=$id, " + diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration98.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration98.kt new file mode 100644 index 00000000..91003fd9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration98.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-16. + */ + +package pl.szczodrzynski.edziennik.data.db.migration + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration98 : Migration(97, 98) { + override fun migrate(database: SupportSQLiteDatabase) { + // timetable colors - override color in lesson object + database.execSQL("ALTER TABLE timetable ADD COLUMN color INT DEFAULT NULL;") + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt index 1e4d9773..55250151 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt @@ -328,7 +328,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { lesson.getNoteSubstituteText(showNotes = true) ?: lesson.displaySubjectName val (subjectTextPrimary, subjectTextSecondary) = if (profileConfig.timetableColorSubjectName) { - val subjectColor = Colors.stringToMaterialColorCRC(lessonText?.toString() ?: "") + val subjectColor = lesson.color ?: Colors.stringToMaterialColorCRC(lessonText?.toString() ?: "") if (lb.annotationVisible) { lb.subjectContainer.background = ColorDrawable(subjectColor) } else { From cf255078509be3b28a6f529e2cb68dcb8d370c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 16 Oct 2022 18:41:37 +0200 Subject: [PATCH 15/53] [API/Usos] Save lecturers as teachers. Add team class. --- .../data/api/edziennik/usos/data/UsosApi.kt | 8 +++ .../data/api/edziennik/usos/data/UsosData.kt | 7 +- .../edziennik/usos/data/api/UsosApiCourses.kt | 5 +- .../edziennik/usos/data/api/UsosApiUser.kt | 72 +++++++++++++++++++ .../edziennik/data/api/models/Data.kt | 28 +++++--- 5 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiUser.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt index 829fefa4..d81eff58 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -41,6 +41,14 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { protected fun JsonObject.getLangString(key: String) = this.getJsonObject(key)?.getString("pl") + protected fun JsonObject.getLecturerIds(key: String) = + this.getJsonArray(key)?.asJsonObjectList()?.mapNotNull { + val id = it.getLong("id") ?: return@mapNotNull null + val firstName = it.getString("first_name") ?: return@mapNotNull null + val lastName = it.getString("last_name") ?: return@mapNotNull null + data.getTeacher(firstName, lastName, id = id).id + } ?: listOf() + private fun valueToString(value: Any) = when (value) { is String -> value is Number -> value.toString() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt index 6f3b6039..d688bebf 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.usos.* import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiCourses import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTerms import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTimetable +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiUser import pl.szczodrzynski.edziennik.utils.Utils.d class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { @@ -41,10 +42,10 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) { d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync") when (endpointId) { - /*ENDPOINT_USOS_API_USER -> { + ENDPOINT_USOS_API_USER -> { data.startProgress(R.string.edziennik_progress_endpoint_student_info) -// TemplateWebSample(data, lastSync, onSuccess) - }*/ + UsosApiUser(data, lastSync, onSuccess) + } ENDPOINT_USOS_API_TERMS -> { data.startProgress(R.string.edziennik_progress_endpoint_school_info) UsosApiTerms(data, lastSync, onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt index 613d9f08..e93c63dd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiCourses.kt @@ -36,7 +36,7 @@ class UsosApiCourses( "group_number", // "class_type", "class_type_id", - // "lecturers", + "lecturers", ), ), ), @@ -69,6 +69,7 @@ class UsosApiCourses( val groupNumber = userGroup.getInt("group_number") ?: continue // val classType = userGroup.getLangString("class_type") ?: continue val classTypeId = userGroup.getString("class_type_id") ?: continue + val lecturers = userGroup.getLecturerIds("lecturers") data.teamList.put(courseUnitId, Team( profileId, @@ -76,7 +77,7 @@ class UsosApiCourses( "${profile?.studentClassName} $classTypeId$groupNumber - $courseName", 2, "${data.schoolId}:${courseId} $classTypeId$groupNumber", - -1, + lecturers.firstOrNull() ?: -1L, )) hasValidTeam = true } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiUser.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiUser.kt new file mode 100644 index 00000000..29a3e22b --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiUser.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-16. + */ + +package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api + +import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_USER +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi +import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.ext.* + +class UsosApiUser( + override val data: DataUsos, + override val lastSync: Long?, + val onSuccess: (endpointId: Int) -> Unit, +) : UsosApi(data, lastSync) { + companion object { + const val TAG = "UsosApiUser" + } + + init { + apiRequest( + tag = TAG, + service = "users/user", + params = mapOf( + "fields" to listOf( + "id", + "first_name", + "last_name", + "student_number", + "student_programmes" to listOf( + "programme" to listOf("id"), + ), + ), + ), + responseType = ResponseType.OBJECT, + ) { json, response -> + val programmes = json.getJsonArray("student_programmes") + if (programmes.isNullOrEmpty()) { + data.error(ApiError(TAG, ERROR_USOS_NO_STUDENT_PROGRAMMES) + .withApiResponse(json) + .withResponse(response)) + return@apiRequest + } + + val firstName = json.getString("first_name") + val lastName = json.getString("last_name") + val studentName = buildFullName(firstName, lastName) + + data.studentId = json.getInt("id") ?: data.studentId + profile?.studentNameLong = studentName + profile?.studentNameShort = studentName.getShortName() + profile?.studentNumber = json.getInt("student_number", -1) + profile?.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id") + + profile?.studentClassName?.let { + data.getTeam( + id = null, + name = it, + schoolCode = data.schoolId ?: "", + isTeamClass = true, + ) + } + + data.setSyncNext(ENDPOINT_USOS_API_USER, 4 * DAY) + onSuccess(ENDPOINT_USOS_API_USER) + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt index c02c666a..9b7137fc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt @@ -449,14 +449,14 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt return team } - fun getTeacher(firstName: String, lastName: String, loginId: String? = null): Teacher { + fun getTeacher(firstName: String, lastName: String, loginId: String? = null, id: Long? = null): Teacher { val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" } - return validateTeacher(teacher, firstName, lastName, loginId) + return validateTeacher(teacher, firstName, lastName, loginId, id) } fun getTeacher(firstNameChar: Char, lastName: String, loginId: String? = null): Teacher { val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" } - return validateTeacher(teacher, firstNameChar.toString(), lastName, loginId) + return validateTeacher(teacher, firstNameChar.toString(), lastName, loginId, null) } fun getTeacherByLastFirst(nameLastFirst: String, loginId: String? = null): Teacher { @@ -464,9 +464,9 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt val teacher = teacherList.singleOrNull { it.fullNameLastFirst == nameLastFirst } val nameParts = nameLastFirst.split(" ", limit = 2) return if (nameParts.size == 1) - validateTeacher(teacher, nameParts[0], "", loginId) + validateTeacher(teacher, nameParts[0], "", loginId, null) else - validateTeacher(teacher, nameParts[1], nameParts[0], loginId) + validateTeacher(teacher, nameParts[1], nameParts[0], loginId, null) } fun getTeacherByFirstLast(nameFirstLast: String, loginId: String? = null): Teacher { @@ -474,9 +474,9 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt val teacher = teacherList.singleOrNull { it.fullName == nameFirstLast } val nameParts = nameFirstLast.split(" ", limit = 2) return if (nameParts.size == 1) - validateTeacher(teacher, nameParts[0], "", loginId) + validateTeacher(teacher, nameParts[0], "", loginId, null) else - validateTeacher(teacher, nameParts[0], nameParts[1], loginId) + validateTeacher(teacher, nameParts[0], nameParts[1], loginId, null) } fun getTeacherByFDotLast(nameFDotLast: String, loginId: String? = null): Teacher { @@ -495,10 +495,16 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt getTeacher(nameParts[0][0], nameParts[1], loginId) } - private fun validateTeacher(teacher: Teacher?, firstName: String, lastName: String, loginId: String?): Teacher { - val obj = teacher ?: Teacher(profileId, -1, firstName, lastName, loginId).apply { - id = fullName.crc32() - teacherList[id] = this + private fun validateTeacher( + teacher: Teacher?, + firstName: String, + lastName: String, + loginId: String?, + id: Long? + ): Teacher { + val obj = teacher ?: Teacher(profileId, -1, firstName, lastName, loginId).also { + it.id = id ?: it.fullName.crc32() + teacherList[it.id] = it } return obj.also { if (loginId != null) From dc19043f73e85e8361973a428fe5e43df5e9736c Mon Sep 17 00:00:00 2001 From: kuba2k2 Date: Mon, 17 Oct 2022 12:56:07 +0200 Subject: [PATCH 16/53] [API/Usos] Implement basic error handling. --- .../edziennik/data/api/Errors.kt | 1 + .../data/api/edziennik/usos/data/UsosApi.kt | 31 ++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt index 8be89c6e..93a7228f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Errors.kt @@ -204,6 +204,7 @@ const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702 const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703 const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704 const val ERROR_USOS_API_INCOMPLETE_RESPONSE = 705 +const val ERROR_USOS_API_MISSING_RESPONSE = 706 const val ERROR_TEMPLATE_WEB_OTHER = 801 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt index d81eff58..9f716d50 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosApi.kt @@ -13,8 +13,10 @@ import im.wangchao.mhttp.callback.JsonArrayCallbackHandler import im.wangchao.mhttp.callback.JsonCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE +import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_MISSING_RESPONSE import pl.szczodrzynski.edziennik.data.api.SERVER_USER_AGENT import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d @@ -141,7 +143,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { ) = when (responseType) { ResponseType.OBJECT -> object : JsonCallbackHandler() { override fun onSuccess(data: JsonObject?, response: Response) { - processResponse(response, data as T, onSuccess) + processResponse(tag, response, data as T?, onSuccess) } override fun onFailure(response: Response?, throwable: Throwable?) { @@ -150,7 +152,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } ResponseType.ARRAY -> object : JsonArrayCallbackHandler() { override fun onSuccess(data: JsonArray?, response: Response) { - processResponse(response, data as T, onSuccess) + processResponse(tag, response, data as T?, onSuccess) } override fun onFailure(response: Response?, throwable: Throwable?) { @@ -159,7 +161,7 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } ResponseType.PLAIN -> object : TextCallbackHandler() { override fun onSuccess(data: String?, response: Response) { - processResponse(response, data as T, onSuccess) + processResponse(tag, response, data as T?, onSuccess) } override fun onFailure(response: Response?, throwable: Throwable?) { @@ -169,11 +171,30 @@ open class UsosApi(open val data: DataUsos, open val lastSync: Long?) { } private fun processResponse( + tag: String, response: Response, - data: T, + value: T?, onSuccess: (data: T, response: Response?) -> Unit, ) { - onSuccess(data, response) + val errorCode = when { + response.code() == HTTP_UNAUTHORIZED -> { + data.oauthTokenKey = null + data.oauthTokenSecret = null + data.oauthTokenIsUser = false + data.oauthLoginResponse = null + UsosLoginApi(data) { } + return + } + value == null -> ERROR_USOS_API_MISSING_RESPONSE + response.code() == HTTP_OK -> { + onSuccess(value, response) + null + } + else -> response.toErrorCode() + } + if (errorCode != null) { + data.error(tag, errorCode, response, value.toString()) + } } private fun processError( From 3ab9602865073a5dbb47e45be6484063021e5e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 17 Oct 2022 16:06:13 +0200 Subject: [PATCH 17/53] [API/Usos] Fix re-logging in after user action. --- .../data/api/edziennik/usos/login/UsosLoginApi.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt index 11172d7d..06651477 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLoginApi.kt @@ -10,10 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError -import pl.szczodrzynski.edziennik.ext.Bundle -import pl.szczodrzynski.edziennik.ext.fromQueryString -import pl.szczodrzynski.edziennik.ext.toBundle -import pl.szczodrzynski.edziennik.ext.toQueryString +import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { @@ -25,6 +22,9 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { init { run { + data.arguments?.getString("oauthLoginResponse")?.let { + data.oauthLoginResponse = it + } if (data.isApiLoginValid()) { onSuccess() } else if (data.oauthLoginResponse != null) { @@ -36,6 +36,8 @@ class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) { } private fun authorize() { + data.oauthTokenKey = null + data.oauthTokenSecret = null api.apiRequest( tag = TAG, service = "oauth/request_token", From 52a53334cac01a47726b41e6296b169e69a1b6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 17 Oct 2022 22:30:23 +0200 Subject: [PATCH 18/53] [Strings] Add USOS error descriptions. --- app/src/main/res/values/errors.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/res/values/errors.xml b/app/src/main/res/values/errors.xml index a3b498da..557eaea8 100644 --- a/app/src/main/res/values/errors.xml +++ b/app/src/main/res/values/errors.xml @@ -30,6 +30,7 @@ ERROR_LOGIN_METHOD_NOT_SATISFIED ERROR_NOT_IMPLEMENTED ERROR_FILE_DOWNLOAD + ERROR_REQUIRES_USER_ACTION ERROR_API_PDO_ERROR ERROR_API_INVALID_CLIENT @@ -169,6 +170,12 @@ ERROR_PODLASIE_API_OTHER ERROR_PODLASIE_API_DATA_MISSING + ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN + ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE + ERROR_USOS_NO_STUDENT_PROGRAMMES + ERROR_USOS_API_INCOMPLETE_RESPONSE + ERROR_USOS_API_MISSING_RESPONSE + ERROR_TEMPLATE_WEB_OTHER EXCEPTION_API_TASK @@ -215,6 +222,7 @@ Nie można wywołać metody logowania. Skontaktuj się z twórcą aplikacji. Nie zaimplementowano Wystąpił błąd podczas pobierania pliku. Dziennik może być przeciążony lub mieć przerwę techniczną. + Wymagana akcja w aplikacji ERROR_API_PDO_ERROR Nieprawidłowy ID klienta API @@ -354,6 +362,12 @@ ERROR_PODLASIE_API_OTHER Brak danych. Zgłoś błąd programiście. + Błąd logowania: otrzymano nieprawidłowy token + Błąd logowania: niekompletna odpowiedź serwera + Student nie jest zapisany na żaden kierunek + Brakujące dane w odpowiedzi serwera + Brakująca odpowiedź serwera + ERROR_TEMPLATE_WEB_OTHER Błąd synchronizacji. Upewnij się, że masz połączenie z internetem, a następnie zgłoś błąd. From 6f12227c2ef8d9fe73185c50989417cba1893f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 17 Oct 2022 22:56:22 +0200 Subject: [PATCH 19/53] [4.13-beta.1] Update build.gradle, signing and changelog. --- app/src/main/assets/pl-changelog.html | 11 +++++------ app/src/main/cpp/szkolny-signing.cpp | 2 +- .../edziennik/data/api/szkolny/interceptor/Signing.kt | 2 +- build.gradle | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index 2548b456..d57022f1 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,10 +1,9 @@ -

Wersja 4.12.1, 2022-09-23

+

Wersja 4.13-beta.1, 2022-10-17

    -
  • Vulcan UONET+: naprawiono działanie systemu wiadomości. @Antoni-Czaplicki
  • -
  • Vulcan UONET+: naprawiono błędy wersji 4.11.9 i starszych.
  • -
  • Poprawiono wyświetlanie lekcji odwołanych na stronie głównej.
  • -
  • Dodano dostęp do Laboratorium na ekranie logowania.
  • -
  • Usunięto obsługę dziennika EduDziennik. [*]
  • +
  • Poprawione powiadomienia na Androidzie 13. @santoni0
  • +
  • Możliwość dostosowania wyświetlania planu lekcji
  • +
  • Opcja kolorowania bloków w planie lekcji
  • +
  • USOS - pierwsza wersja obsługi systemu


diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index 639ca56e..57774985 100644 --- a/app/src/main/cpp/szkolny-signing.cpp +++ b/app/src/main/cpp/szkolny-signing.cpp @@ -9,7 +9,7 @@ /*secret password - removed for source code publication*/ static toys AES_IV[16] = { - 0xdf, 0xe4, 0x2d, 0xa3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0x12, 0xdd, 0xb2, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt index 24f28c3c..068268ca 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt @@ -46,6 +46,6 @@ object Signing { /*fun provideKey(param1: String, param2: Long): ByteArray {*/ fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { - return "$param1.MTIzNDU2Nzg5MDJgAI/q8c===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MD5fPgIjyZ===.$param2".sha256() } } diff --git a/build.gradle b/build.gradle index 7b8133d1..038ced0b 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { kotlin_version = '1.6.10' release = [ - versionName: "4.12.1", - versionCode: 4120199 + versionName: "4.13-beta.1", + versionCode: 4130001 ] setup = [ From 2ec06bc39aacd622f1ad02592ccde5403c1d6e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 18 Oct 2022 11:49:46 +0200 Subject: [PATCH 20/53] [UI] Fix timetable lesson height. Add missing timetable settings. --- .../edziennik/ui/settings/cards/SettingsRegisterCard.kt | 9 ++++++++- .../edziennik/ui/timetable/TimetableDayFragment.kt | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt index 3b6b51f9..0d574419 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt @@ -54,6 +54,13 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { } override fun getItems() = listOfNotNull( + util.createActionItem( + text = R.string.menu_timetable_config, + icon = CommunityMaterial.Icon3.cmd_timetable + ) { + TimetableConfigDialog(activity, reloadOnDismiss = false).show() + }, + util.createActionItem( text = R.string.menu_agenda_config, icon = CommunityMaterial.Icon.cmd_calendar_outline @@ -70,7 +77,7 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { util.createActionItem( text = R.string.menu_messages_config, - icon = CommunityMaterial.Icon.cmd_calendar_outline + icon = CommunityMaterial.Icon.cmd_email_outline ) { MessagesConfigDialog(activity, reloadOnDismiss = false).show() }, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt index 55250151..b901cdfc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt @@ -85,7 +85,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { startHour = startHour, endHour = endHour, dividerHeight = 1.dp, - halfHourHeight = if (app.profile.loginStoreType == LOGIN_TYPE_USOS) 45.dp else 30.dp, + halfHourHeight = if (app.profile.loginStoreType == LOGIN_TYPE_USOS) 45.dp else 60.dp, hourDividerColor = R.attr.hourDividerColor.resolveAttr(context), halfHourDividerColor = R.attr.halfHourDividerColor.resolveAttr(context), hourLabelWidth = 40.dp, From 1450d63fcbb7b4f479f8d6cc1a0795e8f5088bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 18 Oct 2022 22:06:18 +0200 Subject: [PATCH 21/53] [4.13-beta.2] Update build.gradle, signing and changelog. --- app/src/main/assets/pl-changelog.html | 2 +- app/src/main/cpp/szkolny-signing.cpp | 2 +- .../edziennik/data/api/szkolny/interceptor/Signing.kt | 2 +- build.gradle | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index d57022f1..4630e25a 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,4 +1,4 @@ -

Wersja 4.13-beta.1, 2022-10-17

+

Wersja 4.13-beta.2, 2022-10-18

  • Poprawione powiadomienia na Androidzie 13. @santoni0
  • Możliwość dostosowania wyświetlania planu lekcji
  • diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index 57774985..bf07fd34 100644 --- a/app/src/main/cpp/szkolny-signing.cpp +++ b/app/src/main/cpp/szkolny-signing.cpp @@ -9,7 +9,7 @@ /*secret password - removed for source code publication*/ static toys AES_IV[16] = { - 0x12, 0xdd, 0xb2, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0xde, 0xd4, 0xce, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt index 068268ca..3fafc6b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt @@ -46,6 +46,6 @@ object Signing { /*fun provideKey(param1: String, param2: Long): ByteArray {*/ fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { - return "$param1.MTIzNDU2Nzg5MD5fPgIjyZ===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MDl2tMYSgy===.$param2".sha256() } } diff --git a/build.gradle b/build.gradle index 038ced0b..9dfdc8c2 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { kotlin_version = '1.6.10' release = [ - versionName: "4.13-beta.1", - versionCode: 4130001 + versionName: "4.13-beta.2", + versionCode: 4130002 ] setup = [ From ba10d10a104ac45a203c2fcdeb62c8ad8d1689f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 20 Oct 2022 21:58:10 +0200 Subject: [PATCH 22/53] [API] Refactor integer-based types to enum classes. (#145) * [App] Add enum classes for common IDs. * [App] Rename enum package names. * [App] Migrate code to use new enums. * [DB] Migrate loginStoreMode IDs to be unique. * [UI] Fix minor issues after refactor. * [API] Update sync method signature. * [UI] Correct pop-to-home and back button drawer behavior. * [App] Update Bundle extensions usage. * [App] Migrate notification types to enum. * [UI] Make Lab fragment compatible with enums. * [API] Make EndpointTimer use FeatureType. * [App] Migrate config & API lists to sets. --- .../99.json | 2314 +++++++++++++++++ .../java/pl/szczodrzynski/edziennik/App.kt | 15 +- .../szczodrzynski/edziennik/MainActivity.kt | 776 ++---- .../edziennik/config/ConfigUI.kt | 10 +- .../edziennik/config/ProfileConfigSync.kt | 10 +- .../config/utils/AppConfigMigrationV3.kt | 32 +- .../edziennik/config/utils/ConfigMigration.kt | 17 +- .../config/utils/ProfileConfigMigration.kt | 4 +- .../edziennik/data/api/EndpointChooser.kt | 143 +- .../edziennik/data/api/Features.kt | 86 - .../edziennik/data/api/LoginMethods.kt | 148 -- .../data/api/edziennik/EdziennikTask.kt | 35 +- .../data/api/edziennik/ProfileArchiver.kt | 22 +- .../data/api/edziennik/librus/DataLibrus.kt | 13 +- .../data/api/edziennik/librus/Librus.kt | 48 +- .../api/edziennik/librus/LibrusFeatures.kt | 196 +- .../api/edziennik/librus/data/LibrusData.kt | 6 +- .../api/LibrusApiAnnouncementMarkAsRead.kt | 3 +- .../librus/data/api/LibrusApiAnnouncements.kt | 3 +- .../librus/data/api/LibrusApiAttendances.kt | 3 +- .../data/api/LibrusApiBehaviourGrades.kt | 7 +- .../data/api/LibrusApiDescriptiveGrades.kt | 3 +- .../librus/data/api/LibrusApiEvents.kt | 3 +- .../librus/data/api/LibrusApiGradeComments.kt | 1 - .../librus/data/api/LibrusApiGrades.kt | 3 +- .../librus/data/api/LibrusApiHomework.kt | 3 +- .../librus/data/api/LibrusApiLessons.kt | 1 - .../librus/data/api/LibrusApiLuckyNumber.kt | 3 +- .../librus/data/api/LibrusApiNotices.kt | 3 +- .../librus/data/api/LibrusApiPointGrades.kt | 3 +- .../librus/data/api/LibrusApiPtMeetings.kt | 3 +- .../librus/data/api/LibrusApiSchools.kt | 2 - .../librus/data/api/LibrusApiSubjects.kt | 1 - .../data/api/LibrusApiTeacherFreeDays.kt | 8 +- .../librus/data/api/LibrusApiTextGrades.kt | 3 +- .../librus/data/api/LibrusApiTimetables.kt | 3 +- .../data/messages/LibrusMessagesGetList.kt | 20 +- .../data/messages/LibrusMessagesGetMessage.kt | 3 +- .../messages/LibrusMessagesSendMessage.kt | 2 +- .../data/synergia/LibrusSynergiaGetMessage.kt | 3 +- .../synergia/LibrusSynergiaGetMessages.kt | 7 +- .../data/synergia/LibrusSynergiaHomework.kt | 7 +- ...ibrusSynergiaMarkAllAnnouncementsAsRead.kt | 3 +- .../librus/firstlogin/LibrusFirstLogin.kt | 16 +- .../api/edziennik/librus/login/LibrusLogin.kt | 40 +- .../edziennik/librus/login/LibrusLoginApi.kt | 12 +- .../librus/login/LibrusLoginMessages.kt | 3 +- .../librus/login/LibrusLoginPortal.kt | 3 +- .../librus/login/LibrusLoginSynergia.kt | 3 +- .../librus/login/SynergiaTokenExtractor.kt | 3 +- .../mobidziennik/DataMobidziennik.kt | 6 +- .../edziennik/mobidziennik/Mobidziennik.kt | 30 +- .../mobidziennik/MobidziennikFeatures.kt | 100 +- .../mobidziennik/data/MobidziennikData.kt | 6 +- .../data/api/MobidziennikApiAttendance.kt | 3 +- .../data/api/MobidziennikApiEvents.kt | 3 +- .../data/api/MobidziennikApiGrades.kt | 3 +- .../data/api/MobidziennikApiHomework.kt | 3 +- .../data/api/MobidziennikApiNotices.kt | 3 +- .../data/api/MobidziennikApiTimetable.kt | 3 +- .../web/MobidziennikLuckyNumberExtractor.kt | 3 +- .../data/web/MobidziennikWebAttendance.kt | 3 +- .../data/web/MobidziennikWebCalendar.kt | 3 +- .../data/web/MobidziennikWebGetMessage.kt | 3 +- .../data/web/MobidziennikWebGrades.kt | 3 +- .../data/web/MobidziennikWebMessagesAll.kt | 3 +- .../data/web/MobidziennikWebMessagesInbox.kt | 3 +- .../data/web/MobidziennikWebMessagesSent.kt | 7 +- .../data/web/MobidziennikWebSendMessage.kt | 5 +- .../data/web/MobidziennikWebTimetable.kt | 3 +- .../firstlogin/MobidziennikFirstLogin.kt | 10 +- .../mobidziennik/login/MobidziennikLogin.kt | 30 +- .../api/edziennik/podlasie/DataPodlasie.kt | 4 +- .../data/api/edziennik/podlasie/Podlasie.kt | 12 +- .../edziennik/podlasie/PodlasieFeatures.kt | 12 +- .../edziennik/podlasie/data/PodlasieData.kt | 6 +- .../podlasie/data/api/PodlasieApiEvents.kt | 3 +- .../data/api/PodlasieApiFinalGrades.kt | 5 +- .../podlasie/data/api/PodlasieApiGrades.kt | 3 +- .../podlasie/data/api/PodlasieApiHomework.kt | 3 +- .../data/api/PodlasieApiLuckyNumber.kt | 3 +- .../podlasie/firstlogin/PodlasieFirstLogin.kt | 11 +- .../edziennik/podlasie/login/PodlasieLogin.kt | 25 +- .../api/edziennik/template/DataTemplate.kt | 7 +- .../data/api/edziennik/template/Template.kt | 12 +- .../edziennik/template/TemplateFeatures.kt | 22 +- .../edziennik/template/data/TemplateData.kt | 6 +- .../template/data/api/TemplateApiSample.kt | 6 +- .../template/data/web/TemplateWebSample.kt | 7 +- .../template/data/web/TemplateWebSample2.kt | 6 +- .../edziennik/template/login/TemplateLogin.kt | 30 +- .../data/api/edziennik/usos/DataUsos.kt | 4 +- .../edziennik/data/api/edziennik/usos/Usos.kt | 15 +- .../data/api/edziennik/usos/UsosFeatures.kt | 27 +- .../data/api/edziennik/usos/data/UsosData.kt | 6 +- .../usos/data/api/UsosApiTimetable.kt | 3 +- .../usos/firstlogin/UsosFirstLogin.kt | 10 +- .../api/edziennik/usos/login/UsosLogin.kt | 25 +- .../data/api/edziennik/vulcan/DataVulcan.kt | 7 +- .../data/api/edziennik/vulcan/Vulcan.kt | 28 +- .../api/edziennik/vulcan/VulcanFeatures.kt | 86 +- .../api/edziennik/vulcan/data/VulcanData.kt | 6 +- .../vulcan/data/hebe/VulcanHebeAttendance.kt | 3 +- .../vulcan/data/hebe/VulcanHebeExams.kt | 3 +- .../data/hebe/VulcanHebeGradeSummary.kt | 3 +- .../vulcan/data/hebe/VulcanHebeGrades.kt | 3 +- .../vulcan/data/hebe/VulcanHebeHomework.kt | 3 +- .../vulcan/data/hebe/VulcanHebeLuckyNumber.kt | 3 +- .../vulcan/data/hebe/VulcanHebeMain.kt | 5 +- .../vulcan/data/hebe/VulcanHebeMessages.kt | 7 +- .../hebe/VulcanHebeMessagesChangeStatus.kt | 3 +- .../vulcan/data/hebe/VulcanHebeNotices.kt | 3 +- .../vulcan/data/hebe/VulcanHebeSendMessage.kt | 2 +- .../vulcan/data/hebe/VulcanHebeTimetable.kt | 3 +- .../vulcan/data/web/VulcanWebLuckyNumber.kt | 3 +- .../vulcan/firstlogin/VulcanFirstLogin.kt | 3 +- .../api/edziennik/vulcan/login/VulcanLogin.kt | 30 +- .../data/api/interfaces/EdziennikCallback.kt | 1 - .../data/api/interfaces/EdziennikInterface.kt | 5 +- .../data/api/interfaces/EndpointCallback.kt | 1 - .../edziennik/data/api/models/Data.kt | 14 +- .../edziennik/data/api/models/Feature.kt | 22 +- .../edziennik/data/api/models/LoginMethod.kt | 46 - .../edziennik/data/api/szkolny/SzkolnyApi.kt | 4 +- .../edziennik/data/api/task/AppSync.kt | 3 +- .../edziennik/data/api/task/Notifications.kt | 85 +- .../data/api/task/PostNotifications.kt | 44 +- .../szczodrzynski/edziennik/data/db/AppDb.kt | 6 +- .../data/db/converter/ConverterEnums.kt | 36 + .../edziennik/data/db/dao/AnnouncementDao.kt | 3 +- .../edziennik/data/db/dao/AttendanceDao.kt | 2 +- .../edziennik/data/db/dao/EventDao.kt | 9 +- .../edziennik/data/db/dao/GradeDao.kt | 2 +- .../edziennik/data/db/dao/LuckyNumberDao.kt | 2 +- .../edziennik/data/db/dao/MessageDao.kt | 2 +- .../edziennik/data/db/dao/MetadataDao.java | 104 +- .../edziennik/data/db/dao/NoticeDao.kt | 2 +- .../data/db/dao/TeacherAbsenceDao.kt | 2 +- .../edziennik/data/db/dao/TimetableDao.kt | 2 +- .../edziennik/data/db/entity/EndpointTimer.kt | 15 +- .../edziennik/data/db/entity/LoginStore.kt | 41 +- .../edziennik/data/db/entity/Metadata.java | 50 +- .../edziennik/data/db/entity/Notification.kt | 55 +- .../edziennik/data/db/entity/Profile.kt | 67 +- .../edziennik/data/db/enums/FeatureType.kt | 35 + .../edziennik/data/db/enums/LoginMethod.kt | 84 + .../edziennik/data/db/enums/LoginMode.kt | 20 + .../edziennik/data/db/enums/LoginType.kt | 39 + .../edziennik/data/db/enums/MetadataType.kt | 20 + .../data/db/enums/NotificationType.kt | 134 + .../data/db/migration/Migration58.kt | 5 +- .../data/db/migration/Migration68.kt | 4 +- .../data/db/migration/Migration71.kt | 4 +- .../data/db/migration/Migration81.kt | 4 +- .../data/db/migration/Migration85.kt | 4 +- .../data/db/migration/Migration94.kt | 4 +- .../data/db/migration/Migration99.kt | 15 + .../data/firebase/SzkolnyAppFirebase.kt | 35 +- .../data/firebase/SzkolnyLibrusFirebase.kt | 50 +- .../firebase/SzkolnyMobidziennikFirebase.kt | 22 +- .../data/firebase/SzkolnyVulcanFirebase.kt | 20 +- .../edziennik/ext/BundleExtensions.kt | 72 +- .../edziennik/ext/DataExtensions.kt | 27 - .../edziennik/ext/EnumExtensions.kt | 75 + .../edziennik/ext/JsonExtensions.kt | 17 +- .../edziennik/ui/agenda/AgendaFragment.kt | 3 +- .../announcements/AnnouncementsFragment.java | 14 +- .../ui/attendance/AttendanceFragment.kt | 3 +- .../edziennik/ui/base/enums/NavTarget.kt | 242 ++ .../ui/base/enums/NavTargetLocation.kt | 14 + .../ui/behaviour/BehaviourFragment.java | 6 +- .../edziennik/ui/behaviour/NoticesAdapter.kt | 4 +- .../edziennik/ui/debug/LabPageFragment.kt | 2 +- .../edziennik/ui/debug/LabProfileFragment.kt | 33 +- .../ui/dialogs/ProfileRemoveDialog.kt | 2 +- .../edziennik/ui/dialogs/base/BaseDialog.kt | 20 +- .../edziennik/ui/dialogs/base/ViewDialog.kt | 2 +- .../ui/dialogs/settings/AppLanguageDialog.kt | 2 +- .../dialogs/settings/MiniMenuConfigDialog.kt | 44 +- .../settings/NotificationFilterDialog.kt | 42 +- .../ui/dialogs/settings/SyncIntervalDialog.kt | 2 +- .../ui/dialogs/settings/ThemeChooserDialog.kt | 2 +- .../ui/dialogs/sync/ServerMessageDialog.kt | 2 +- .../ui/dialogs/sync/SyncViewListDialog.kt | 61 +- .../ui/dialogs/sync/UpdateAvailableDialog.kt | 2 +- .../edziennik/ui/error/ErrorDetailsDialog.kt | 2 +- .../edziennik/ui/event/EventDetailsDialog.kt | 9 +- .../edziennik/ui/event/EventManualDialog.kt | 10 +- .../edziennik/ui/grades/GradesListFragment.kt | 8 +- .../edziennik/ui/home/HomeConfigDialog.kt | 2 +- .../edziennik/ui/home/HomeFragment.kt | 3 +- .../ui/home/cards/HomeArchiveCard.kt | 5 +- .../edziennik/ui/home/cards/HomeEventsCard.kt | 3 +- .../edziennik/ui/home/cards/HomeGradesCard.kt | 3 +- .../edziennik/ui/home/cards/HomeNotesCard.kt | 3 +- .../ui/home/cards/HomeTimetableCard.kt | 12 +- .../edziennik/ui/homework/HomeworkFragment.kt | 3 +- .../ui/login/LoginChooserFragment.kt | 20 +- .../edziennik/ui/login/LoginFinishFragment.kt | 5 +- .../edziennik/ui/login/LoginFormFragment.kt | 10 +- .../edziennik/ui/login/LoginInfo.kt | 38 +- .../ui/login/LoginPlatformListFragment.kt | 9 +- .../ui/login/LoginProgressFragment.kt | 7 +- .../edziennik/ui/login/LoginSyncFragment.kt | 2 +- .../compose/MessagesComposeFragment.kt | 36 +- .../ui/messages/list/MessagesFragment.kt | 5 +- .../ui/messages/list/MessagesListFragment.kt | 9 +- .../ui/messages/single/MessageFragment.kt | 12 +- .../ui/notifications/NotificationsAdapter.kt | 4 +- .../NotificationsListFragment.kt | 4 +- .../ui/settings/cards/SettingsRegisterCard.kt | 4 +- .../ui/settings/cards/SettingsSyncCard.kt | 3 +- .../edziennik/ui/teachers/TeachersAdapter.kt | 3 +- .../edziennik/ui/template/TemplateAdapter.kt | 2 +- .../timetable/GenerateBlockTimetableDialog.kt | 5 +- .../ui/timetable/TimetableDayFragment.kt | 14 +- .../ui/timetable/TimetableFragment.kt | 3 +- .../ui/widgets/LessonDialogActivity.kt | 13 +- .../ui/widgets/WidgetConfigActivity.java | 3 +- .../luckynumber/WidgetLuckyNumberProvider.kt | 4 +- .../WidgetNotificationsFactory.kt | 12 +- .../WidgetNotificationsProvider.kt | 4 +- .../timetable/WidgetTimetableProvider.kt | 4 +- .../edziennik/utils/BetterLink.kt | 3 +- .../edziennik/utils/PausedNavigationData.kt | 19 +- .../utils/managers/AvailabilityManager.kt | 14 +- .../utils/managers/MessageManager.kt | 5 +- .../edziennik/utils/models/NavTarget.kt | 97 - .../edziennik/utils/models/UnreadCounter.kt | 8 +- app/src/main/res/values/strings.xml | 2 +- 230 files changed, 4620 insertions(+), 2415 deletions(-) create mode 100644 app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/Features.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/LoginMethod.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/converter/ConverterEnums.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMethod.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMode.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/MetadataType.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/NotificationType.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration99.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ext/EnumExtensions.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTarget.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTargetLocation.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/models/NavTarget.kt diff --git a/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json new file mode 100644 index 00000000..7db65929 --- /dev/null +++ b/app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/99.json @@ -0,0 +1,2314 @@ +{ + "formatVersion": 1, + "database": { + "version": 99, + "identityHash": "2612ebba9802eedc7ebc69724606a23c", + "entities": [ + { + "tableName": "grades", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `gradeId` INTEGER NOT NULL, `gradeName` TEXT NOT NULL, `gradeType` INTEGER NOT NULL, `gradeValue` REAL NOT NULL, `gradeWeight` REAL NOT NULL, `gradeColor` INTEGER NOT NULL, `gradeCategory` TEXT, `gradeDescription` TEXT, `gradeComment` TEXT, `gradeSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `gradeValueMax` REAL, `gradeClassAverage` REAL, `gradeParentId` INTEGER, `gradeIsImprovement` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `gradeId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "gradeId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "gradeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "gradeType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "gradeValue", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "gradeWeight", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "gradeColor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "gradeCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "description", + "columnName": "gradeDescription", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "comment", + "columnName": "gradeComment", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "semester", + "columnName": "gradeSemester", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "valueMax", + "columnName": "gradeValueMax", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "classAverage", + "columnName": "gradeClassAverage", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "parentId", + "columnName": "gradeParentId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isImprovement", + "columnName": "gradeIsImprovement", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "gradeId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_grades_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_grades_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "teachers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `teacherLoginId` TEXT, `teacherName` TEXT, `teacherSurname` TEXT, `teacherType` INTEGER NOT NULL, `teacherTypeDescription` TEXT, `teacherSubjects` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "loginId", + "columnName": "teacherLoginId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "name", + "columnName": "teacherName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "surname", + "columnName": "teacherSurname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "teacherType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "typeDescription", + "columnName": "teacherTypeDescription", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subjects", + "columnName": "teacherSubjects", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teacherId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "teacherAbsence", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceId` INTEGER NOT NULL, `teacherAbsenceType` INTEGER NOT NULL, `teacherAbsenceName` TEXT, `teacherAbsenceDateFrom` TEXT NOT NULL, `teacherAbsenceDateTo` TEXT NOT NULL, `teacherAbsenceTimeFrom` TEXT, `teacherAbsenceTimeTo` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teacherAbsenceId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "teacherAbsenceType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "teacherAbsenceName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "dateFrom", + "columnName": "teacherAbsenceDateFrom", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateTo", + "columnName": "teacherAbsenceDateTo", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timeFrom", + "columnName": "teacherAbsenceTimeFrom", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timeTo", + "columnName": "teacherAbsenceTimeTo", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teacherAbsenceId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_teacherAbsence_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_teacherAbsence_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "teacherAbsenceTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teacherAbsenceTypeId` INTEGER NOT NULL, `teacherAbsenceTypeName` TEXT NOT NULL, PRIMARY KEY(`profileId`, `teacherAbsenceTypeId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teacherAbsenceTypeId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "teacherAbsenceTypeName", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teacherAbsenceTypeId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "subjects", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `subjectLongName` TEXT, `subjectShortName` TEXT, `subjectColor` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `subjectId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "longName", + "columnName": "subjectLongName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "shortName", + "columnName": "subjectShortName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "color", + "columnName": "subjectColor", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "subjectId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "notices", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noticeId` INTEGER NOT NULL, `noticeType` INTEGER NOT NULL, `noticeSemester` INTEGER NOT NULL, `noticeText` TEXT NOT NULL, `noticeCategory` TEXT, `noticePoints` REAL, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `noticeId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "noticeId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "noticeType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "semester", + "columnName": "noticeSemester", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "noticeText", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "category", + "columnName": "noticeCategory", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "points", + "columnName": "noticePoints", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "noticeId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_notices_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_notices_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "teams", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `teamType` INTEGER NOT NULL, `teamName` TEXT, `teamCode` TEXT, `teamTeacherId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `teamId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "teamType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "teamName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "code", + "columnName": "teamCode", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teamTeacherId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "teamId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendances", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `attendanceId` INTEGER NOT NULL, `attendanceBaseType` INTEGER NOT NULL, `attendanceTypeName` TEXT NOT NULL, `attendanceTypeShort` TEXT NOT NULL, `attendanceTypeSymbol` TEXT NOT NULL, `attendanceTypeColor` INTEGER, `attendanceDate` TEXT NOT NULL, `attendanceTime` TEXT, `attendanceSemester` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `attendanceLessonTopic` TEXT, `attendanceLessonNumber` INTEGER, `attendanceIsCounted` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `attendanceId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "attendanceId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "baseType", + "columnName": "attendanceBaseType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "typeName", + "columnName": "attendanceTypeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeShort", + "columnName": "attendanceTypeShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeSymbol", + "columnName": "attendanceTypeSymbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeColor", + "columnName": "attendanceTypeColor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "date", + "columnName": "attendanceDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "attendanceTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "semester", + "columnName": "attendanceSemester", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lessonTopic", + "columnName": "attendanceLessonTopic", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lessonNumber", + "columnName": "attendanceLessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "isCounted", + "columnName": "attendanceIsCounted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "attendanceId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_attendances_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_attendances_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "events", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventId` INTEGER NOT NULL, `eventDate` TEXT NOT NULL, `eventTime` TEXT, `eventTopic` TEXT NOT NULL, `eventColor` INTEGER, `eventType` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `eventAddedManually` INTEGER NOT NULL, `eventSharedBy` TEXT, `eventSharedByName` TEXT, `eventBlacklisted` INTEGER NOT NULL, `eventIsDone` INTEGER NOT NULL, `eventIsDownloaded` INTEGER NOT NULL, `homeworkBody` TEXT, `attachmentIds` TEXT, `attachmentNames` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "eventId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "eventDate", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "time", + "columnName": "eventTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "topic", + "columnName": "eventTopic", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "eventColor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "eventType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedManually", + "columnName": "eventAddedManually", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "sharedBy", + "columnName": "eventSharedBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedByName", + "columnName": "eventSharedByName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "blacklisted", + "columnName": "eventBlacklisted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDone", + "columnName": "eventIsDone", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isDownloaded", + "columnName": "eventIsDownloaded", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "homeworkBody", + "columnName": "homeworkBody", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentIds", + "columnName": "attachmentIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentNames", + "columnName": "attachmentNames", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "eventId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_events_profileId_eventDate_eventTime", + "unique": false, + "columnNames": [ + "profileId", + "eventDate", + "eventTime" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventDate_eventTime` ON `${TABLE_NAME}` (`profileId`, `eventDate`, `eventTime`)" + }, + { + "name": "index_events_profileId_eventType", + "unique": false, + "columnNames": [ + "profileId", + "eventType" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_events_profileId_eventType` ON `${TABLE_NAME}` (`profileId`, `eventType`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "eventTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `eventType` INTEGER NOT NULL, `eventTypeName` TEXT NOT NULL, `eventTypeColor` INTEGER NOT NULL, `eventTypeOrder` INTEGER NOT NULL, `eventTypeSource` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `eventType`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "eventType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "eventTypeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "eventTypeColor", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "order", + "columnName": "eventTypeOrder", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "source", + "columnName": "eventTypeSource", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "eventType" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "loginStores", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `loginStoreMode` INTEGER NOT NULL, `loginStoreData` TEXT NOT NULL, PRIMARY KEY(`loginStoreId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "loginStoreId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "loginStoreType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "mode", + "columnName": "loginStoreMode", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "data", + "columnName": "loginStoreData", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "loginStoreId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "profiles", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `loginStoreId` INTEGER NOT NULL, `loginStoreType` INTEGER NOT NULL, `name` TEXT NOT NULL, `subname` TEXT, `studentNameLong` TEXT NOT NULL, `studentNameShort` TEXT NOT NULL, `accountName` TEXT, `studentData` TEXT NOT NULL, `image` TEXT, `empty` INTEGER NOT NULL, `archived` INTEGER NOT NULL, `archiveId` INTEGER, `syncEnabled` INTEGER NOT NULL, `enableSharedEvents` INTEGER NOT NULL, `registration` INTEGER NOT NULL, `userCode` TEXT NOT NULL, `studentNumber` INTEGER NOT NULL, `studentClassName` TEXT, `studentSchoolYearStart` INTEGER NOT NULL, `dateSemester1Start` TEXT NOT NULL, `dateSemester2Start` TEXT NOT NULL, `dateYearEnd` TEXT NOT NULL, `disabledNotifications` TEXT, `lastReceiversSync` INTEGER NOT NULL, PRIMARY KEY(`profileId`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "loginStoreId", + "columnName": "loginStoreId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "loginStoreType", + "columnName": "loginStoreType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "subname", + "columnName": "subname", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentNameLong", + "columnName": "studentNameLong", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentNameShort", + "columnName": "studentNameShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accountName", + "columnName": "accountName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentData", + "columnName": "studentData", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "image", + "columnName": "image", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "empty", + "columnName": "empty", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "archived", + "columnName": "archived", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "archiveId", + "columnName": "archiveId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "syncEnabled", + "columnName": "syncEnabled", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "enableSharedEvents", + "columnName": "enableSharedEvents", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "registration", + "columnName": "registration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userCode", + "columnName": "userCode", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "studentNumber", + "columnName": "studentNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "studentClassName", + "columnName": "studentClassName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "studentSchoolYearStart", + "columnName": "studentSchoolYearStart", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "dateSemester1Start", + "columnName": "dateSemester1Start", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateSemester2Start", + "columnName": "dateSemester2Start", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "dateYearEnd", + "columnName": "dateYearEnd", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "disabledNotifications", + "columnName": "disabledNotifications", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lastReceiversSync", + "columnName": "lastReceiversSync", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "luckyNumbers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `luckyNumberDate` INTEGER NOT NULL, `luckyNumber` INTEGER NOT NULL, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `luckyNumberDate`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "luckyNumberDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "number", + "columnName": "luckyNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "luckyNumberDate" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "announcements", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `announcementId` INTEGER NOT NULL, `announcementSubject` TEXT NOT NULL, `announcementText` TEXT, `announcementStartDate` TEXT, `announcementEndDate` TEXT, `teacherId` INTEGER NOT NULL, `addedDate` INTEGER NOT NULL, `announcementIdString` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `announcementId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "announcementId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "announcementSubject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "announcementText", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "startDate", + "columnName": "announcementStartDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endDate", + "columnName": "announcementEndDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "idString", + "columnName": "announcementIdString", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "announcementId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_announcements_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_announcements_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "gradeCategories", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `categoryId` INTEGER NOT NULL, `weight` REAL NOT NULL, `color` INTEGER NOT NULL, `text` TEXT, `columns` TEXT, `valueFrom` REAL NOT NULL, `valueTo` REAL NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `categoryId`, `type`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "categoryId", + "columnName": "categoryId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "weight", + "columnName": "weight", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "columns", + "columnName": "columns", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "valueFrom", + "columnName": "valueFrom", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "valueTo", + "columnName": "valueTo", + "affinity": "REAL", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "categoryId", + "type" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "feedbackMessages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `received` INTEGER NOT NULL, `text` TEXT NOT NULL, `senderName` TEXT NOT NULL, `deviceId` TEXT, `deviceName` TEXT, `devId` INTEGER, `devImage` TEXT, `sentTime` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "received", + "columnName": "received", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "senderName", + "columnName": "senderName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "deviceId", + "columnName": "deviceId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "deviceName", + "columnName": "deviceName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "devId", + "columnName": "devId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "devImage", + "columnName": "devImage", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sentTime", + "columnName": "sentTime", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "messageId" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "messages", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, `messageType` INTEGER NOT NULL, `messageSubject` TEXT NOT NULL, `messageBody` TEXT, `senderId` INTEGER, `addedDate` INTEGER NOT NULL, `messageIsPinned` INTEGER NOT NULL, `hasAttachments` INTEGER NOT NULL, `attachmentIds` TEXT, `attachmentNames` TEXT, `attachmentSizes` TEXT, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "messageId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "messageType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subject", + "columnName": "messageSubject", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "body", + "columnName": "messageBody", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "senderId", + "columnName": "senderId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isStarred", + "columnName": "messageIsPinned", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "hasAttachments", + "columnName": "hasAttachments", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "attachmentIds", + "columnName": "attachmentIds", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentNames", + "columnName": "attachmentNames", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "attachmentSizes", + "columnName": "attachmentSizes", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "messageId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_messages_profileId_messageType", + "unique": false, + "columnNames": [ + "profileId", + "messageType" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_messages_profileId_messageType` ON `${TABLE_NAME}` (`profileId`, `messageType`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "messageRecipients", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `messageRecipientId` INTEGER NOT NULL, `messageRecipientReplyId` INTEGER NOT NULL, `messageRecipientReadDate` INTEGER NOT NULL, `messageId` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `messageRecipientId`, `messageId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "messageRecipientId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "replyId", + "columnName": "messageRecipientReplyId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "readDate", + "columnName": "messageRecipientReadDate", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "messageId", + "columnName": "messageId", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "messageRecipientId", + "messageId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "debugLogs", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "endpointTimers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `endpointId` INTEGER NOT NULL, `endpointLastSync` INTEGER, `endpointNextSync` INTEGER NOT NULL, `endpointViewId` INTEGER, PRIMARY KEY(`profileId`, `endpointId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "endpointId", + "columnName": "endpointId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastSync", + "columnName": "endpointLastSync", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "nextSync", + "columnName": "endpointNextSync", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewId", + "columnName": "endpointViewId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "endpointId" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "lessonRanges", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonRangeNumber` INTEGER NOT NULL, `lessonRangeStart` TEXT NOT NULL, `lessonRangeEnd` TEXT NOT NULL, PRIMARY KEY(`profileId`, `lessonRangeNumber`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lessonNumber", + "columnName": "lessonRangeNumber", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "startTime", + "columnName": "lessonRangeStart", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "endTime", + "columnName": "lessonRangeEnd", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "lessonRangeNumber" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "notifications", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL, `textLong` TEXT, `type` INTEGER NOT NULL, `profileId` INTEGER, `profileName` TEXT, `posted` INTEGER NOT NULL, `viewId` INTEGER, `extras` TEXT, `addedDate` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "text", + "columnName": "text", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "textLong", + "columnName": "textLong", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "profileName", + "columnName": "profileName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "posted", + "columnName": "posted", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "viewId", + "columnName": "viewId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "extras", + "columnName": "extras", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "classrooms", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "noticeTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "attendanceTypes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `baseType` INTEGER NOT NULL, `typeName` TEXT NOT NULL, `typeShort` TEXT NOT NULL, `typeSymbol` TEXT NOT NULL, `typeColor` INTEGER, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "baseType", + "columnName": "baseType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "typeName", + "columnName": "typeName", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeShort", + "columnName": "typeShort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeSymbol", + "columnName": "typeSymbol", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "typeColor", + "columnName": "typeColor", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "timetable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `id` INTEGER NOT NULL, `type` INTEGER NOT NULL, `date` TEXT, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT, `oldDate` TEXT, `oldLessonNumber` INTEGER, `oldStartTime` TEXT, `oldEndTime` TEXT, `oldSubjectId` INTEGER, `oldTeacherId` INTEGER, `oldTeamId` INTEGER, `oldClassroom` TEXT, `isExtra` INTEGER NOT NULL, `color` INTEGER, `keep` INTEGER NOT NULL, PRIMARY KEY(`profileId`, `id`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "lessonNumber", + "columnName": "lessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "classroom", + "columnName": "classroom", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldDate", + "columnName": "oldDate", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldLessonNumber", + "columnName": "oldLessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldStartTime", + "columnName": "oldStartTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldEndTime", + "columnName": "oldEndTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "oldSubjectId", + "columnName": "oldSubjectId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldTeacherId", + "columnName": "oldTeacherId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldTeamId", + "columnName": "oldTeamId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "oldClassroom", + "columnName": "oldClassroom", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isExtra", + "columnName": "isExtra", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "color", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "keep", + "columnName": "keep", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "id" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_timetable_profileId_type_date", + "unique": false, + "columnNames": [ + "profileId", + "type", + "date" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_date` ON `${TABLE_NAME}` (`profileId`, `type`, `date`)" + }, + { + "name": "index_timetable_profileId_type_oldDate", + "unique": false, + "columnNames": [ + "profileId", + "type", + "oldDate" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetable_profileId_type_oldDate` ON `${TABLE_NAME}` (`profileId`, `type`, `oldDate`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "config", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `key` TEXT NOT NULL, `value` TEXT, PRIMARY KEY(`profileId`, `key`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "key", + "columnName": "key", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "value", + "columnName": "value", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "key" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "librusLessons", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `lessonId` INTEGER NOT NULL, `teacherId` INTEGER NOT NULL, `subjectId` INTEGER NOT NULL, `teamId` INTEGER, PRIMARY KEY(`profileId`, `lessonId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lessonId", + "columnName": "lessonId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "profileId", + "lessonId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_librusLessons_profileId", + "unique": false, + "columnNames": [ + "profileId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_librusLessons_profileId` ON `${TABLE_NAME}` (`profileId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "timetableManual", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `repeatBy` INTEGER NOT NULL, `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` INTEGER, `weekDay` INTEGER, `lessonNumber` INTEGER, `startTime` TEXT, `endTime` TEXT, `subjectId` INTEGER, `teacherId` INTEGER, `teamId` INTEGER, `classroom` TEXT)", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "repeatBy", + "columnName": "repeatBy", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "date", + "columnName": "date", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "weekDay", + "columnName": "weekDay", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "lessonNumber", + "columnName": "lessonNumber", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "startTime", + "columnName": "startTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "endTime", + "columnName": "endTime", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "subjectId", + "columnName": "subjectId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teacherId", + "columnName": "teacherId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "teamId", + "columnName": "teamId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "classroom", + "columnName": "classroom", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_timetableManual_profileId_date", + "unique": false, + "columnNames": [ + "profileId", + "date" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_date` ON `${TABLE_NAME}` (`profileId`, `date`)" + }, + { + "name": "index_timetableManual_profileId_weekDay", + "unique": false, + "columnNames": [ + "profileId", + "weekDay" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_timetableManual_profileId_weekDay` ON `${TABLE_NAME}` (`profileId`, `weekDay`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "notes", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `noteId` INTEGER NOT NULL, `noteOwnerType` TEXT, `noteOwnerId` INTEGER, `noteReplacesOriginal` INTEGER NOT NULL, `noteTopic` TEXT, `noteBody` TEXT NOT NULL, `noteColor` INTEGER, `noteSharedBy` TEXT, `noteSharedByName` TEXT, `addedDate` INTEGER NOT NULL, PRIMARY KEY(`noteId`))", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "noteId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "ownerType", + "columnName": "noteOwnerType", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "ownerId", + "columnName": "noteOwnerId", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "replacesOriginal", + "columnName": "noteReplacesOriginal", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "topic", + "columnName": "noteTopic", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "body", + "columnName": "noteBody", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "color", + "columnName": "noteColor", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "sharedBy", + "columnName": "noteSharedBy", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "sharedByName", + "columnName": "noteSharedByName", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "addedDate", + "columnName": "addedDate", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "noteId" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_notes_profileId_noteOwnerType_noteOwnerId", + "unique": false, + "columnNames": [ + "profileId", + "noteOwnerType", + "noteOwnerId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_notes_profileId_noteOwnerType_noteOwnerId` ON `${TABLE_NAME}` (`profileId`, `noteOwnerType`, `noteOwnerId`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "metadata", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`profileId` INTEGER NOT NULL, `metadataId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `thingType` INTEGER NOT NULL, `thingId` INTEGER NOT NULL, `seen` INTEGER NOT NULL, `notified` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "profileId", + "columnName": "profileId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "metadataId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "thingType", + "columnName": "thingType", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "thingId", + "columnName": "thingId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "seen", + "columnName": "seen", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "notified", + "columnName": "notified", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "metadataId" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_metadata_profileId_thingType_thingId", + "unique": true, + "columnNames": [ + "profileId", + "thingType", + "thingId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_metadata_profileId_thingType_thingId` ON `${TABLE_NAME}` (`profileId`, `thingType`, `thingId`)" + } + ], + "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, '2612ebba9802eedc7ebc69724606a23c')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 56886775..1dcea55b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -37,14 +37,17 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.MS +import pl.szczodrzynski.edziennik.ext.putExtras import pl.szczodrzynski.edziennik.ext.setLanguage import pl.szczodrzynski.edziennik.network.SSLProviderInstaller import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar import pl.szczodrzynski.edziennik.sync.SyncWorker import pl.szczodrzynski.edziennik.sync.UpdateWorker import pl.szczodrzynski.edziennik.ui.base.CrashActivity +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.* import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.managers.* @@ -180,7 +183,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { // initialize companion object values App.db = AppDb(this) App.config = Config(App.db) - App.profile = Profile(0, 0, 0, "") + App.profile = Profile(0, 0, LoginType.TEMPLATE, "") debugMode = BuildConfig.DEBUG devMode = config.devMode ?: debugMode enableChucker = config.enableChucker ?: devMode @@ -224,35 +227,35 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { .setShortLabel(getString(R.string.shortcut_timetable)).setLongLabel(getString(R.string.shortcut_timetable)) .setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_timetable)) .setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java) - .putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE)) + .putExtras("fragmentId" to NavTarget.TIMETABLE)) .build() val shortcutAgenda = ShortcutInfo.Builder(this@App, "item_agenda") .setShortLabel(getString(R.string.shortcut_agenda)).setLongLabel(getString(R.string.shortcut_agenda)) .setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_agenda)) .setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java) - .putExtra("fragmentId", MainActivity.DRAWER_ITEM_AGENDA)) + .putExtras("fragmentId" to NavTarget.AGENDA)) .build() val shortcutGrades = ShortcutInfo.Builder(this@App, "item_grades") .setShortLabel(getString(R.string.shortcut_grades)).setLongLabel(getString(R.string.shortcut_grades)) .setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_grades)) .setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java) - .putExtra("fragmentId", MainActivity.DRAWER_ITEM_GRADES)) + .putExtras("fragmentId" to NavTarget.GRADES)) .build() val shortcutHomework = ShortcutInfo.Builder(this@App, "item_homeworks") .setShortLabel(getString(R.string.shortcut_homework)).setLongLabel(getString(R.string.shortcut_homework)) .setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_homework)) .setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java) - .putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOMEWORK)) + .putExtras("fragmentId" to NavTarget.HOMEWORK)) .build() val shortcutMessages = ShortcutInfo.Builder(this@App, "item_messages") .setShortLabel(getString(R.string.shortcut_messages)).setLongLabel(getString(R.string.shortcut_messages)) .setIcon(Icon.createWithResource(this@App, R.mipmap.ic_shortcut_messages)) .setIntent(Intent(Intent.ACTION_MAIN, null, this@App, MainActivity::class.java) - .putExtra("fragmentId", MainActivity.DRAWER_ITEM_MESSAGES)) + .putExtras("fragmentId" to NavTarget.MESSAGES)) .build() shortcutManager.dynamicShortcuts = listOf( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 000f9be6..072e8550 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -28,7 +28,6 @@ import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.materialdrawer.model.* import com.mikepenz.materialdrawer.model.interfaces.* import com.mikepenz.materialdrawer.model.utils.hiddenInMiniDrawer -import eu.szkolny.font.SzkolnyFont import kotlinx.coroutines.* import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe @@ -40,21 +39,19 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.* import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Metadata.* import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent import pl.szczodrzynski.edziennik.sync.SyncWorker import pl.szczodrzynski.edziennik.sync.UpdateWorker -import pl.szczodrzynski.edziennik.ui.agenda.AgendaFragment -import pl.szczodrzynski.edziennik.ui.announcements.AnnouncementsFragment -import pl.szczodrzynski.edziennik.ui.attendance.AttendanceFragment import pl.szczodrzynski.edziennik.ui.base.MainSnackbar -import pl.szczodrzynski.edziennik.ui.behaviour.BehaviourFragment -import pl.szczodrzynski.edziennik.ui.debug.DebugFragment -import pl.szczodrzynski.edziennik.ui.debug.LabFragment +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget +import pl.szczodrzynski.edziennik.ui.base.enums.NavTargetLocation import pl.szczodrzynski.edziennik.ui.dialogs.ChangelogDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog @@ -64,30 +61,15 @@ import pl.szczodrzynski.edziennik.ui.dialogs.sync.UpdateAvailableDialog import pl.szczodrzynski.edziennik.ui.error.ErrorDetailsDialog import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar import pl.szczodrzynski.edziennik.ui.event.EventManualDialog -import pl.szczodrzynski.edziennik.ui.feedback.FeedbackFragment -import pl.szczodrzynski.edziennik.ui.grades.GradesListFragment -import pl.szczodrzynski.edziennik.ui.grades.editor.GradesEditorFragment -import pl.szczodrzynski.edziennik.ui.home.HomeFragment -import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment import pl.szczodrzynski.edziennik.ui.login.LoginActivity -import pl.szczodrzynski.edziennik.ui.login.LoginProgressFragment -import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment -import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment -import pl.szczodrzynski.edziennik.ui.notes.NotesFragment -import pl.szczodrzynski.edziennik.ui.notifications.NotificationsListFragment -import pl.szczodrzynski.edziennik.ui.settings.ProfileManagerFragment -import pl.szczodrzynski.edziennik.ui.settings.SettingsFragment -import pl.szczodrzynski.edziennik.ui.teachers.TeachersListFragment import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment -import pl.szczodrzynski.edziennik.ui.webpush.WebPushFragment import pl.szczodrzynski.edziennik.utils.* import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.dpToPx import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type import pl.szczodrzynski.edziennik.utils.managers.UserActionManager import pl.szczodrzynski.edziennik.utils.models.Date -import pl.szczodrzynski.edziennik.utils.models.NavTarget import pl.szczodrzynski.navlib.* import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet @@ -101,184 +83,8 @@ import kotlin.coroutines.CoroutineContext import kotlin.math.roundToInt class MainActivity : AppCompatActivity(), CoroutineScope { - @Suppress("MemberVisibilityCanBePrivate") companion object { - - const val TAG = "MainActivity" - - const val DRAWER_PROFILE_ADD_NEW = 200 - const val DRAWER_PROFILE_SYNC_ALL = 201 - const val DRAWER_PROFILE_MANAGE = 203 - const val DRAWER_PROFILE_MARK_ALL_AS_READ = 204 - const val DRAWER_ITEM_HOME = 1 - const val DRAWER_ITEM_TIMETABLE = 11 - const val DRAWER_ITEM_AGENDA = 12 - const val DRAWER_ITEM_GRADES = 13 - const val DRAWER_ITEM_MESSAGES = 17 - const val DRAWER_ITEM_HOMEWORK = 14 - const val DRAWER_ITEM_BEHAVIOUR = 15 - const val DRAWER_ITEM_ATTENDANCE = 16 - const val DRAWER_ITEM_ANNOUNCEMENTS = 18 - const val DRAWER_ITEM_NOTIFICATIONS = 20 - const val DRAWER_ITEM_MORE = 21 - const val DRAWER_ITEM_TEACHERS = 22 - const val DRAWER_ITEM_NOTES = 23 - const val DRAWER_ITEM_SETTINGS = 101 - const val DRAWER_ITEM_DEBUG = 102 - - const val TARGET_GRADES_EDITOR = 501 - const val TARGET_FEEDBACK = 120 - const val TARGET_MESSAGES_DETAILS = 503 - const val TARGET_MESSAGES_COMPOSE = 504 - const val TARGET_WEB_PUSH = 140 - const val TARGET_LAB = 1000 - - const val HOME_ID = DRAWER_ITEM_HOME - - val navTargetList: List by lazy { - val list: MutableList = mutableListOf() - val moreList: MutableList = mutableListOf() - - moreList += NavTarget( - id = DRAWER_ITEM_NOTES, - name = R.string.menu_notes, - fragmentClass = NotesFragment::class) - .withIcon(CommunityMaterial.Icon3.cmd_text_box_multiple_outline) - .isStatic(true) - - moreList += NavTarget(DRAWER_ITEM_TEACHERS, - R.string.menu_teachers, - TeachersListFragment::class) - .withIcon(CommunityMaterial.Icon3.cmd_shield_account_outline) - .isStatic(true) - - // home item - list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class) - .withTitle(R.string.app_name) - .withIcon(CommunityMaterial.Icon2.cmd_home_outline) - .isInDrawer(true) - .isStatic(true) - .withPopToHome(false) - - list += NavTarget(DRAWER_ITEM_TIMETABLE, - R.string.menu_timetable, - TimetableFragment::class) - .withIcon(CommunityMaterial.Icon3.cmd_timetable) - .withBadgeTypeId(TYPE_LESSON_CHANGE) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_calendar_outline) - .withBadgeTypeId(TYPE_EVENT) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesListFragment::class) - .withIcon(CommunityMaterial.Icon3.cmd_numeric_5_box_outline) - .withBadgeTypeId(TYPE_GRADE) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_email_outline) - .withBadgeTypeId(TYPE_MESSAGE) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class) - .withIcon(SzkolnyFont.Icon.szf_notebook_outline) - .withBadgeTypeId(TYPE_HOMEWORK) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_BEHAVIOUR, - R.string.menu_notices, - BehaviourFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_emoticon_outline) - .withBadgeTypeId(TYPE_NOTICE) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_ATTENDANCE, - R.string.menu_attendance, - AttendanceFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline) - .withBadgeTypeId(TYPE_ATTENDANCE) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, - R.string.menu_announcements, - AnnouncementsFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline) - .withBadgeTypeId(TYPE_ANNOUNCEMENT) - .isInDrawer(true) - - list += NavTarget(DRAWER_ITEM_MORE, R.string.menu_more, null) - .withIcon(CommunityMaterial.Icon.cmd_dots_horizontal) - .isInDrawer(true) - .isStatic(true) - .withSubItems(*moreList.toTypedArray()) - - - // static drawer items - list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, - R.string.menu_notifications, - NotificationsListFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline) - .isInDrawer(true) - .isStatic(true) - .isBelowSeparator(true) - - list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsFragment::class) - .withIcon(CommunityMaterial.Icon.cmd_cog_outline) - .isInDrawer(true) - .isStatic(true) - .isBelowSeparator(true) - - - // profile settings items - list += NavTarget(DRAWER_PROFILE_ADD_NEW, R.string.menu_add_new_profile, null) - .withIcon(CommunityMaterial.Icon3.cmd_plus) - .withDescription(R.string.drawer_add_new_profile_desc) - .isInProfileList(true) - - list += NavTarget(DRAWER_PROFILE_MANAGE, - R.string.menu_manage_profiles, - ProfileManagerFragment::class) - .withTitle(R.string.title_profile_manager) - .withIcon(CommunityMaterial.Icon.cmd_account_group) - .withDescription(R.string.drawer_manage_profiles_desc) - .isInProfileList(false) - - list += NavTarget(DRAWER_PROFILE_MARK_ALL_AS_READ, - R.string.menu_mark_everything_as_read, - null) - .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) - .isInProfileList(true) - - list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null) - .withIcon(CommunityMaterial.Icon.cmd_download_outline) - .isInProfileList(true) - - - // other target items, not directly navigated - list += NavTarget(TARGET_GRADES_EDITOR, - R.string.menu_grades_editor, - GradesEditorFragment::class) - list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class) - list += NavTarget(TARGET_MESSAGES_DETAILS, - R.string.menu_message, - MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES) - list += NavTarget(TARGET_MESSAGES_COMPOSE, - R.string.menu_message_compose, - MessagesComposeFragment::class) - list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class) - if (App.devMode) { - list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class) - list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class) - .withIcon(CommunityMaterial.Icon2.cmd_flask_outline) - .isInDrawer(true) - .isBelowSeparator(true) - .isStatic(true) - } - - list - } + private const val TAG = "MainActivity" } private var job = Job() @@ -296,18 +102,16 @@ class MainActivity : AppCompatActivity(), CoroutineScope { val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout } var onBeforeNavigate: (() -> Boolean)? = null - var pausedNavigationData: PausedNavigationData? = null - private set + private var pausedNavigationData: PausedNavigationData? = null val app: App by lazy { applicationContext as App } private val fragmentManager by lazy { supportFragmentManager } - private lateinit var navTarget: NavTarget + lateinit var navTarget: NavTarget + private set private var navArguments: Bundle? = null - val navTargetId - get() = navTarget.id private val navBackStack = mutableListOf>() private var navLoading = true @@ -371,7 +175,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { window.statusBarColor = statusBarColor } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && ColorUtils.calculateLuminance(statusBarColor) > 0.6 + && ColorUtils.calculateLuminance(statusBarColor) > 0.6 ) { @Suppress("deprecation") window.decorView.systemUiVisibility = @@ -418,12 +222,15 @@ class MainActivity : AppCompatActivity(), CoroutineScope { drawerProfileListEmptyListener = { onProfileListEmptyEvent(ProfileListEmptyEvent()) } - drawerItemSelectedListener = { id, _, _ -> - loadTarget(id) + drawerItemSelectedListener = { id, _, item -> + if (item is ExpandableDrawerItem) + false + else + navigate(navTarget = id.asNavTargetOrNull()) } drawerProfileSelectedListener = { id, _, _, _ -> // why is this negated -_- - !loadProfile(id) + !navigate(profileId = id) } drawerProfileLongClickListener = { _, profile, _, view -> if (view != null && profile is ProfileDrawerItem) { @@ -447,7 +254,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } } - navTarget = navTargetList[0] + navTarget = NavTarget.HOME if (savedInstanceState != null) { intent?.putExtras(savedInstanceState) @@ -479,9 +286,6 @@ class MainActivity : AppCompatActivity(), CoroutineScope { handleIntent(intent?.extras) app.db.metadataDao().unreadCounts.observe(this) { unreadCounters -> - unreadCounters.map { - it.type = it.thingType - } drawer.setUnreadCounterList(unreadCounters) } @@ -504,11 +308,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope { app.db.profileDao().getNotArchivedOf(app.profile.archiveId!!) } if (profile != null) - loadProfile(profile) + navigate(profile = profile) else - loadProfile(0) + navigate(profileId = 0) } else { - loadProfile(0) + navigate(profileId = 0) } } } @@ -599,39 +403,32 @@ class MainActivity : AppCompatActivity(), CoroutineScope { .withIcon(CommunityMaterial.Icon.cmd_download_outline) .withOnClickListener { bottomSheet.close() - SyncViewListDialog(this, navTargetId).show() + SyncViewListDialog(this, navTarget).show() }, BottomSheetSeparatorItem(false), - BottomSheetPrimaryItem(false) - .withTitle(R.string.menu_settings) - .withIcon(CommunityMaterial.Icon.cmd_cog_outline) - .withOnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }, - BottomSheetPrimaryItem(false) - .withTitle(R.string.menu_feedback) - .withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline) - .withOnClickListener { loadTarget(TARGET_FEEDBACK) } ) - if (App.devMode) { - bottomSheet += BottomSheetPrimaryItem(false) - .withTitle(R.string.menu_debug) - .withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge) - .withOnClickListener { loadTarget(DRAWER_ITEM_DEBUG) } + for (target in NavTarget.values()) { + if (target.location != NavTargetLocation.BOTTOM_SHEET) + continue + if (target.devModeOnly && !App.devMode) + continue + bottomSheet += target.toBottomSheetItem(this) } } - private var profileSettingClickListener = { id: Int, _: View? -> - when (id) { - DRAWER_PROFILE_ADD_NEW -> { + private var profileSettingClickListener = { itemId: Int, _: View? -> + when (val item = itemId.asNavTarget()) { + NavTarget.PROFILE_ADD -> { requestHandler.requestLogin() } - DRAWER_PROFILE_SYNC_ALL -> { + NavTarget.PROFILE_SYNC_ALL -> { EdziennikTask.sync().enqueue(this) } - DRAWER_PROFILE_MARK_ALL_AS_READ -> { + NavTarget.PROFILE_MARK_AS_READ -> { launch { withContext(Dispatchers.Default) { app.db.profileDao().allNow.forEach { profile -> - if (profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS) + if (profile.loginStoreType != LoginType.LIBRUS) app.db.metadataDao() .setAllSeenExceptMessagesAndAnnouncements(profile.id, true) else @@ -644,7 +441,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } } else -> { - loadTarget(id) + navigate(navTarget = item) } } false @@ -701,7 +498,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { when (error?.type) { Type.NOT_AVAILABLE -> { swipeRefreshLayout.isRefreshing = false - loadTarget(DRAWER_ITEM_HOME) + navigate(navTarget = NavTarget.HOME) RegisterUnavailableDialog(this, error.status!!).show() return } @@ -712,21 +509,25 @@ class MainActivity : AppCompatActivity(), CoroutineScope { Type.NO_API_ACCESS -> { Toast.makeText(this, R.string.error_no_api_access, Toast.LENGTH_SHORT).show() } + else -> {} } swipeRefreshLayout.isRefreshing = true - Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show() - val fragmentParam = when (navTargetId) { - DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection - else -> 0 + Toast.makeText(this, fragmentToSyncName(navTarget), Toast.LENGTH_SHORT).show() + val featureType = when (navTarget) { + NavTarget.MESSAGES -> when (MessagesFragment.pageSelection) { + Message.TYPE_SENT -> FeatureType.MESSAGES_SENT + else -> FeatureType.MESSAGES_INBOX + } + else -> navTarget.featureType } - val arguments = when (navTargetId) { - DRAWER_ITEM_TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d) + val arguments = when (navTarget) { + NavTarget.TIMETABLE -> JsonObject("weekStart" to TimetableFragment.pageSelection?.weekStart?.stringY_m_d) else -> null } EdziennikTask.syncProfile( App.profileId, - listOf(navTargetId to fragmentParam), + featureType?.let { setOf(it) }, arguments = arguments ).enqueue(this) } @@ -859,19 +660,19 @@ class MainActivity : AppCompatActivity(), CoroutineScope { app.userActionManager.execute(this, event, UserActionManager.UserActionCallback()) } - private fun fragmentToSyncName(currentFragment: Int): Int { - return when (currentFragment) { - DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable - DRAWER_ITEM_AGENDA -> R.string.sync_feature_agenda - DRAWER_ITEM_GRADES -> R.string.sync_feature_grades - DRAWER_ITEM_HOMEWORK -> R.string.sync_feature_homework - DRAWER_ITEM_BEHAVIOUR -> R.string.sync_feature_notices - DRAWER_ITEM_ATTENDANCE -> R.string.sync_feature_attendance - DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) { - 1 -> R.string.sync_feature_messages_outbox + private fun fragmentToSyncName(navTarget: NavTarget): Int { + return when (navTarget) { + NavTarget.TIMETABLE -> R.string.sync_feature_timetable + NavTarget.AGENDA -> R.string.sync_feature_agenda + NavTarget.GRADES -> R.string.sync_feature_grades + NavTarget.HOMEWORK -> R.string.sync_feature_homework + NavTarget.BEHAVIOUR -> R.string.sync_feature_notices + NavTarget.ATTENDANCE -> R.string.sync_feature_attendance + NavTarget.MESSAGES -> when (MessagesFragment.pageSelection) { + Message.TYPE_SENT -> R.string.sync_feature_messages_outbox else -> R.string.sync_feature_messages_inbox } - DRAWER_ITEM_ANNOUNCEMENTS -> R.string.sync_feature_announcements + NavTarget.ANNOUNCEMENTS -> R.string.sync_feature_announcements else -> R.string.sync_feature_syncing_all } } @@ -889,15 +690,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } fun handleIntent(extras: Bundle?) { - d(TAG, "handleIntent() {") extras?.keySet()?.forEach { key -> d(TAG, " \"$key\": " + extras.get(key)) } d(TAG, "}") - var intentProfileId = -1 - var intentTargetId = -1 + val intentProfileId = extras.getIntOrNull("profileId") + var intentNavTarget = extras.getIntOrNull("fragmentId").asNavTargetOrNull() if (extras?.containsKey("action") == true) { val handled = when (extras.getString("action")) { @@ -910,7 +710,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { true } "feedbackMessage" -> { - intentTargetId = TARGET_FEEDBACK + intentNavTarget = NavTarget.FEEDBACK false } "userActionRequired" -> { @@ -920,7 +720,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope { params = extras.getBundle("params") ?: return, errorText = 0, ) - app.userActionManager.execute(this, event, UserActionManager.UserActionCallback()) + app.userActionManager.execute(this, + event, + UserActionManager.UserActionCallback()) true } "createManualEvent" -> { @@ -942,72 +744,58 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } if (extras?.containsKey("reloadProfileId") == true) { - val reloadProfileId = extras.getInt("reloadProfileId", -1) - extras.remove("reloadProfileId") + val reloadProfileId = extras.getIntOrNull("reloadProfileId") if (reloadProfileId == -1 || app.profile.id == reloadProfileId) { reloadTarget() return } } - if (extras?.getInt("profileId", -1) != -1) { - intentProfileId = extras.getInt("profileId", -1) - extras?.remove("profileId") - } - - if (extras?.getInt("fragmentId", -1) != -1) { - intentTargetId = extras.getInt("fragmentId", -1) - extras?.remove("fragmentId") - } + extras?.remove("profileId") + extras?.remove("fragmentId") + extras?.remove("reloadProfileId") /*if (intentTargetId == -1 && navController.currentDestination?.id == R.id.loadingFragment) { intentTargetId = navTarget.id }*/ - if (navLoading) { + if (navLoading) b.fragment.removeAllViews() - if (intentTargetId == -1) - intentTargetId = HOME_ID - } when { - app.profile.id == 0 -> { - if (intentProfileId == -1) - intentProfileId = app.config.lastProfileId - loadProfile(intentProfileId, intentTargetId, extras) - } - intentProfileId != -1 -> { - if (app.profile.id != intentProfileId) - loadProfile(intentProfileId, intentTargetId, extras) - else - loadTarget(intentTargetId, extras) - } - intentTargetId != -1 -> { - drawer.currentProfile = app.profile.id - if (navTargetId != intentTargetId || navLoading) - loadTarget(intentTargetId, extras) - } - else -> { - drawer.currentProfile = app.profile.id - } + app.profile.id == 0 -> navigate( + profileId = intentProfileId ?: app.config.lastProfileId, + navTarget = intentNavTarget, + args = extras, + ) + intentProfileId != -1 -> navigate( + profileId = intentProfileId, + navTarget = intentNavTarget, + args = extras, + ) + intentNavTarget != null -> navigate( + navTarget = intentNavTarget, + args = extras, + ) + else -> drawer.currentProfile = app.profile.id } navLoading = false } override fun recreate() { - recreate(navTargetId) + recreate(navTarget) } - fun recreate(targetId: Int) { - recreate(targetId, null) + fun recreate(navTarget: NavTarget) { + recreate(navTarget, null) } - fun recreate(targetId: Int? = null, arguments: Bundle? = null) { + fun recreate(navTarget: NavTarget? = null, arguments: Bundle? = null) { val intent = Intent(this, MainActivity::class.java) if (arguments != null) intent.putExtras(arguments) - if (targetId != null) { - intent.putExtra("fragmentId", targetId) + if (navTarget != null) { + intent.putExtra("fragmentId", navTarget.id) } finish() overridePendingTransition(R.anim.fade_in, R.anim.fade_out) @@ -1047,7 +835,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putInt("fragmentId", navTargetId) + outState.putExtras("fragmentId" to navTarget) } override fun onNewIntent(intent: Intent?) { @@ -1077,187 +865,120 @@ class MainActivity : AppCompatActivity(), CoroutineScope { private fun canNavigate(): Boolean = onBeforeNavigate?.invoke() != false fun resumePausedNavigation(): Boolean { - if (pausedNavigationData == null) - return false - pausedNavigationData?.let { data -> - when (data) { - is PausedNavigationData.LoadProfile -> loadProfile( - id = data.id, - drawerSelection = data.drawerSelection, - arguments = data.arguments, - skipBeforeNavigate = true, - ) - is PausedNavigationData.LoadTarget -> loadTarget( - id = data.id, - arguments = data.arguments, - skipBeforeNavigate = true, - ) - else -> return false - } - } + val data = pausedNavigationData ?: return false + navigate( + profileId = data.profileId, + navTarget = data.navTarget, + args = data.args, + skipBeforeNavigate = true, + ) pausedNavigationData = null return true } - fun loadProfile(id: Int) = loadProfile(id, navTargetId) - - // fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments) - fun loadProfile(profile: Profile): Boolean { - if (!canNavigate()) { - pausedNavigationData = PausedNavigationData.LoadProfile( - id = profile.id, - drawerSelection = navTargetId, - arguments = null, - ) - return false - } - - loadProfile(profile, navTargetId, null) - return true - } - - private fun loadProfile( - id: Int, - drawerSelection: Int, - arguments: Bundle? = null, - skipBeforeNavigate: Boolean = false, - ): Boolean { - if (!skipBeforeNavigate && !canNavigate()) { - drawer.close() - // restore the previous profile after changing it with the drawer - // well, it still does not change the toolbar profile image, - // but that's now NavView's problem, not mine. - drawer.currentProfile = app.profile.id - pausedNavigationData = PausedNavigationData.LoadProfile( - id = id, - drawerSelection = drawerSelection, - arguments = arguments, - ) - return false - } - - if (App.profileId == id) { - drawer.currentProfile = app.profile.id - // skipBeforeNavigate because it's checked above already - loadTarget(drawerSelection, arguments, skipBeforeNavigate = true) - return true - } - app.profileLoad(id) { - loadProfile(it, drawerSelection, arguments) - } - return true - } - - private fun loadProfile(profile: Profile, drawerSelection: Int, arguments: Bundle?) { - App.profile = profile - MessagesFragment.pageSelection = -1 - - setDrawerItems() - - val previousArchivedId = if (app.profile.archived) app.profile.id else null - if (previousArchivedId != null) { - // prevents accidentally removing the first item if the archived profile is not shown - drawer.removeProfileById(previousArchivedId) - } - if (profile.archived) { - drawer.prependProfile(Profile( - id = profile.id, - loginStoreId = profile.loginStoreId, - loginStoreType = profile.loginStoreType, - name = profile.name, - subname = "Archiwum - ${profile.subname}" - ).also { - it.archived = true - }) - } - - // the drawer profile is updated automatically when the drawer item is clicked - // update it manually when switching profiles from other source - //if (drawer.currentProfile != app.profile.id) - drawer.currentProfile = app.profileId - loadTarget(drawerSelection, arguments, skipBeforeNavigate = true) - } - - fun loadTarget( - id: Int, - arguments: Bundle? = null, - skipBeforeNavigate: Boolean = false, - ): Boolean { - var loadId = id - if (loadId == -1) { - loadId = DRAWER_ITEM_HOME - } - val targets = navTargetList - .flatMap { it.subItems?.toList() ?: emptyList() } - .plus(navTargetList) - val target = targets.firstOrNull { it.id == loadId } - return when { - target == null -> { - Toast.makeText( - this, - getString(R.string.error_invalid_fragment, id), - Toast.LENGTH_LONG, - ).show() - loadTarget(navTargetList.first(), arguments, skipBeforeNavigate) - } - target.fragmentClass != null -> { - loadTarget(target, arguments, skipBeforeNavigate) - } - else -> { - false - } - } - } - - private fun loadTarget( - target: NavTarget, + fun navigate( + profileId: Int? = null, + profile: Profile? = null, + navTarget: NavTarget? = null, args: Bundle? = null, skipBeforeNavigate: Boolean = false, ): Boolean { - d("NavDebug", "loadTarget(target = $target, args = $args)") - - if (!skipBeforeNavigate && !canNavigate()) { + d(TAG, "navigate(profileId = ${profile?.id ?: profileId}, target = ${navTarget?.name}, args = $args)") + if (!(skipBeforeNavigate || navTarget == this.navTarget) && !canNavigate()) { bottomSheet.close() drawer.close() - pausedNavigationData = PausedNavigationData.LoadTarget( - id = target.id, - arguments = args, - ) + // restore the previous profile if changing it with the drawer + // well, it still does not change the toolbar profile image, + // but that's now NavView's problem, not mine. + drawer.currentProfile = App.profile.id + pausedNavigationData = PausedNavigationData(profileId, navTarget, args) return false } - pausedNavigationData = null + + val loadNavTarget = navTarget ?: this.navTarget + if (profile != null && profile.id != App.profileId) { + navigateImpl(profile, loadNavTarget, args, profileChanged = true) + return true + } + if (profileId != null && profileId != App.profileId) { + app.profileLoad(profileId) { + navigateImpl(it, loadNavTarget, args, profileChanged = true) + } + return true + } + navigateImpl(App.profile, loadNavTarget, args, profileChanged = false) + return true + } + + private fun navigateImpl( + profile: Profile, + navTarget: NavTarget, + args: Bundle?, + profileChanged: Boolean, + ) { + d(TAG, "navigateImpl(profileId = ${profile.id}, target = ${navTarget.name}, args = $args)") + + if (profileChanged) { + App.profile = profile + MessagesFragment.pageSelection = -1 + // set new drawer items for this profile + setDrawerItems() + + val previousArchivedId = if (app.profile.archived) app.profile.id else null + if (previousArchivedId != null) { + // prevents accidentally removing the first item if the archived profile is not shown + drawer.removeProfileById(previousArchivedId) + } + if (profile.archived) { + // add the same profile but with a different name + // (other fields are not needed by the drawer) + drawer.prependProfile(Profile( + id = profile.id, + loginStoreId = profile.loginStoreId, + loginStoreType = profile.loginStoreType, + name = profile.name, + subname = "Archiwum - ${profile.subname}" + ).also { + it.archived = true + }) + } + + // the drawer profile is updated automatically when the drawer item is clicked + // update it manually when switching profiles from other source + //if (drawer.currentProfile != app.profile.id) + drawer.currentProfile = App.profileId + } val arguments = args - ?: navBackStack.firstOrNull { it.first.id == target.id }?.second + ?: navBackStack.firstOrNull { it.first == navTarget }?.second ?: Bundle() bottomSheet.close() bottomSheet.removeAllContextual() bottomSheet.toggleGroupEnabled = false drawer.close() - if (drawer.getSelection() != target.id) - drawer.setSelection(target.id, fireOnClick = false) - navView.toolbar.setTitle(target.title ?: target.name) + if (drawer.getSelection() != navTarget.id) + drawer.setSelection(navTarget.id, fireOnClick = false) + navView.toolbar.setTitle(navTarget.titleRes ?: navTarget.nameRes) navView.bottomBar.fabEnable = false navView.bottomBar.fabExtended = false navView.bottomBar.setFabOnClickListener(null) - d("NavDebug", - "Navigating from ${navTarget.fragmentClass?.java?.simpleName} to ${target.fragmentClass?.java?.simpleName}") + d("NavDebug", "Navigating from ${this.navTarget.name} to ${navTarget.name}") - val fragment = target.fragmentClass?.java?.newInstance() ?: return false + val fragment = navTarget.fragmentClass?.newInstance() ?: return fragment.arguments = arguments val transaction = fragmentManager.beginTransaction() - if (navTarget == target) { + if (navTarget == this.navTarget) { // just reload the current target transaction.setCustomAnimations( R.anim.fade_in, R.anim.fade_out ) } else { - navBackStack.keys().lastIndexOf(target).let { + navBackStack.keys().lastIndexOf(navTarget).let { if (it == -1) - return@let target + return@let navTarget // pop the back stack up until that target transaction.setCustomAnimations( R.anim.task_close_enter, @@ -1276,8 +997,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope { for (i in 0 until popCount) { navBackStack.removeAt(navBackStack.lastIndex) } - navTarget = target - navArguments = arguments + this.navTarget = navTarget + this.navArguments = arguments return@let null }?.let { @@ -1287,13 +1008,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope { R.anim.task_open_enter, R.anim.task_open_exit ) - navBackStack.add(navTarget to navArguments) - navTarget = target - navArguments = arguments + navBackStack.add(this.navTarget to this.navArguments) + this.navTarget = navTarget + this.navArguments = arguments } } - if (navTarget.popToHome) { + if (navTarget.popTo == NavTarget.HOME) { // if the current has popToHome, let only home be in the back stack // probably `if (navTarget.popToHome)` in popBackStack() is not needed now val popCount = navBackStack.size - 1 @@ -1302,10 +1023,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope { } } - d("NavDebug", - "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:") - navBackStack.forEachIndexed { index, target2 -> - d("NavDebug", " - $index: ${target2.first.fragmentClass?.java?.simpleName}") + d("NavDebug", "Current fragment ${navTarget.name}, back stack:") + navBackStack.forEachIndexed { index, item -> + d("NavDebug", " - $index: ${item.first.name}") } transaction.replace(R.id.fragment, fragment) @@ -1317,36 +1037,37 @@ class MainActivity : AppCompatActivity(), CoroutineScope { @Suppress("deprecation") val taskDesc = ActivityManager.TaskDescription( - if (target.id == HOME_ID) + if (navTarget == NavTarget.HOME) getString(R.string.app_name) else - getString(R.string.app_task_format, getString(target.name)), + getString(R.string.app_task_format, getString(navTarget.nameRes)), bm, getColorFromAttr(this, R.attr.colorSurface) ) setTaskDescription(taskDesc) } - return true + return } - fun reloadTarget() = loadTarget(navTarget) + fun reloadTarget() = navigate() private fun popBackStack(skipBeforeNavigate: Boolean = false): Boolean { if (navBackStack.size == 0) { return false } // TODO back stack argument support - when { - navTarget.popToHome -> { - loadTarget(HOME_ID, skipBeforeNavigate = skipBeforeNavigate) - } - navTarget.popTo != null -> { - loadTarget(navTarget.popTo ?: HOME_ID, skipBeforeNavigate = skipBeforeNavigate) - } - else -> { - navBackStack.last().let { - loadTarget(it.first, it.second, skipBeforeNavigate = skipBeforeNavigate) - } + if (navTarget.popTo != null) { + navigate( + navTarget = navTarget.popTo, + skipBeforeNavigate = skipBeforeNavigate, + ) + } else { + navBackStack.last().let { + navigate( + navTarget = it.first, + args = it.second, + skipBeforeNavigate = skipBeforeNavigate, + ) } } return true @@ -1401,33 +1122,32 @@ class MainActivity : AppCompatActivity(), CoroutineScope { | | | | '__/ _` \ \ /\ / / _ \ '__| | | __/ _ \ '_ ` _ \/ __| | |__| | | | (_| |\ V V / __/ | | | || __/ | | | | \__ \ |_____/|_| \__,_| \_/\_/ \___|_| |_|\__\___|_| |_| |_|__*/ - @Suppress("UNUSED_PARAMETER") private fun createDrawerItem(target: NavTarget, level: Int = 1): IDrawerItem<*> { val item = when { - target.subItems != null -> ExpandableDrawerItem() + // target.subItems != null -> ExpandableDrawerItem() level > 1 -> SecondaryDrawerItem() else -> DrawerPrimaryItem() } item.also { it.identifier = target.id.toLong() - it.nameRes = target.name - it.hiddenInMiniDrawer = !app.config.ui.miniMenuButtons.contains(target.id) - it.description = target.description?.toStringHolder() + it.nameRes = target.nameRes + it.descriptionRes = target.descriptionRes ?: -1 it.icon = target.icon?.toImageHolder() + it.hiddenInMiniDrawer = !app.config.ui.miniMenuButtons.contains(target) if (it is DrawerPrimaryItem) - it.appTitle = target.title?.resolveString(this) - if (it is ColorfulBadgeable && target.badgeTypeId != null) + it.appTitle = target.titleRes?.resolveString(this) + if (/* it is ColorfulBadgeable && */ target.badgeType != null) it.badgeStyle = drawer.badgeStyle it.isSelectedBackgroundAnimated = false it.level = level } - if (target.badgeTypeId != null) - drawer.addUnreadCounterType(target.badgeTypeId!!, target.id) + if (target.badgeType != null) + drawer.addUnreadCounterType(target.badgeType.id, target.id) - item.subItems = target.subItems?.map { + /* item.subItems = target.subItems?.map { createDrawerItem(it, level + 1) - }?.toMutableList() ?: mutableListOf() + }?.toMutableList() ?: mutableListOf() */ return item } @@ -1435,66 +1155,66 @@ class MainActivity : AppCompatActivity(), CoroutineScope { fun setDrawerItems() { d("NavDebug", "setDrawerItems() app.profile = ${app.profile}") val drawerItems = arrayListOf>() + val drawerItemsMore = arrayListOf>() + val drawerItemsBottom = arrayListOf>() val drawerProfiles = arrayListOf() - val supportedFragments = app.profile.supportedFragments + for (target in NavTarget.values()) { + if (target.devModeOnly && !App.devMode) + continue + if (target.featureType != null && target.featureType !in app.profile.loginStoreType.features) + continue - targetPopToHomeList.clear() - - var separatorAdded = false - - for (target in navTargetList) { - if (target.isInDrawer && target.isBelowSeparator && !separatorAdded) { - separatorAdded = true - drawerItems += DividerDrawerItem() - } - - if (target.popToHome) - targetPopToHomeList += target.id - - if (target.isInDrawer && ( - target.isStatic - || supportedFragments.isEmpty() - || supportedFragments.contains(target.id)) - ) { - drawerItems += createDrawerItem(target) - if (target.id == 1) { - targetHomeId = target.id + when (target.location) { + NavTargetLocation.DRAWER -> { + drawerItems += createDrawerItem(target, level = 1) } - } - - if (target.isInProfileList) { - drawerProfiles += ProfileSettingDrawerItem().apply { - identifier = target.id.toLong() - nameRes = target.name - if (target.description != null) - descriptionRes = target.description!! - if (target.icon != null) - withIcon(target.icon!!) + NavTargetLocation.DRAWER_MORE -> { + drawerItemsMore += createDrawerItem(target, level = 2) } + NavTargetLocation.DRAWER_BOTTOM -> { + drawerItemsBottom += createDrawerItem(target, level = 1) + } + NavTargetLocation.PROFILE_LIST -> { + drawerProfiles += ProfileSettingDrawerItem().also { + it.identifier = target.id.toLong() + it.nameRes = target.nameRes + it.descriptionRes = target.descriptionRes ?: -1 + it.icon = target.icon?.toImageHolder() + } + } + else -> continue } } + drawerItems += ExpandableDrawerItem().also { + it.identifier = -1L + it.nameRes = R.string.menu_more + it.icon = CommunityMaterial.Icon.cmd_dots_horizontal.toImageHolder() + it.subItems = drawerItemsMore.toMutableList() + it.isSelectedBackgroundAnimated = false + it.isSelectable = false + } + drawerItems += DividerDrawerItem() + drawerItems += drawerItemsBottom + // seems that this cannot be open, because the itemAdapter has Profile items // instead of normal Drawer items... drawer.profileSelectionClose() - drawer.setItems(*drawerItems.toTypedArray()) drawer.removeAllProfileSettings() drawer.addProfileSettings(*drawerProfiles.toTypedArray()) } - private val targetPopToHomeList = arrayListOf() - private var targetHomeId: Int = -1 override fun onBackPressed() { - if (!b.navView.onBackPressed()) { - if (App.config.ui.openDrawerOnBackPressed && ((navTarget.popTo == null && navTarget.popToHome) - || navTarget.id == DRAWER_ITEM_HOME) - ) { - b.navView.drawer.toggle() - } else { + if (App.config.ui.openDrawerOnBackPressed) { + if (drawer.isOpen) + navigateUp() + else if (!navView.onBackPressed()) + drawer.open() + } else { + if (!navView.onBackPressed()) navigateUp() - } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigUI.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigUI.kt index f36652a1..a937ed28 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigUI.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigUI.kt @@ -7,6 +7,8 @@ package pl.szczodrzynski.edziennik.config import pl.szczodrzynski.edziennik.config.utils.get import pl.szczodrzynski.edziennik.config.utils.getIntList import pl.szczodrzynski.edziennik.config.utils.set +import pl.szczodrzynski.edziennik.ext.asNavTargetOrNull +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget class ConfigUI(private val config: Config) { private var mTheme: Int? = null @@ -34,10 +36,10 @@ class ConfigUI(private val config: Config) { get() { mMiniMenuVisible = mMiniMenuVisible ?: config.values.get("miniMenuVisible", false); return mMiniMenuVisible ?: false } set(value) { config.set("miniMenuVisible", value); mMiniMenuVisible = value } - private var mMiniMenuButtons: List? = null - var miniMenuButtons: List - get() { mMiniMenuButtons = mMiniMenuButtons ?: config.values.getIntList("miniMenuButtons", listOf()); return mMiniMenuButtons ?: listOf() } - set(value) { config.set("miniMenuButtons", value); mMiniMenuButtons = value } + private var mMiniMenuButtons: Set? = null + var miniMenuButtons: Set + get() { mMiniMenuButtons = mMiniMenuButtons ?: config.values.getIntList("miniMenuButtons", listOf())?.mapNotNull { it.asNavTargetOrNull() }?.toSet(); return mMiniMenuButtons ?: setOf() } + set(value) { config.set("miniMenuButtons", value.map { it.id }); mMiniMenuButtons = value } private var mOpenDrawerOnBackPressed: Boolean? = null var openDrawerOnBackPressed: Boolean diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigSync.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigSync.kt index 2012bc4b..f8c67630 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigSync.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigSync.kt @@ -6,10 +6,12 @@ package pl.szczodrzynski.edziennik.config import pl.szczodrzynski.edziennik.config.utils.getIntList import pl.szczodrzynski.edziennik.config.utils.set +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType +import pl.szczodrzynski.edziennik.ext.asNotificationTypeOrNull class ProfileConfigSync(private val config: ProfileConfig) { - private var mNotificationFilter: List? = null - var notificationFilter: List - get() { mNotificationFilter = mNotificationFilter ?: config.values.getIntList("notificationFilter", listOf()); return mNotificationFilter ?: listOf() } - set(value) { config.set("notificationFilter", value); mNotificationFilter = value } + private var mNotificationFilter: Set? = null + var notificationFilter: Set + get() { mNotificationFilter = mNotificationFilter ?: config.values.getIntList("notificationFilter", listOf())?.mapNotNull { it.asNotificationTypeOrNull() }?.toSet(); return mNotificationFilter ?: setOf() } + set(value) { config.set("notificationFilter", value.map { it.id }); mNotificationFilter = value } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/AppConfigMigrationV3.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/AppConfigMigrationV3.kt index 78a1d8a6..5af5e1b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/AppConfigMigrationV3.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/AppConfigMigrationV3.kt @@ -8,11 +8,10 @@ import android.content.SharedPreferences import com.google.gson.Gson import com.google.gson.reflect.TypeToken import pl.szczodrzynski.edziennik.BuildConfig -import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.config.Config -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN +import pl.szczodrzynski.edziennik.data.db.enums.LoginType +import pl.szczodrzynski.edziennik.ext.asNavTargetOrNull +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.models.Time import kotlin.math.abs @@ -26,16 +25,17 @@ class AppConfigMigrationV3(p: SharedPreferences, config: Config) { val oldButtons = p.getString("$s.miniDrawerButtonIds", null)?.let { str -> str.replace("[\\[\\]]*".toRegex(), "") .split(",\\s?".toRegex()) - .mapNotNull { it.toIntOrNull() } + .mapNotNull { it.toIntOrNull().asNavTargetOrNull() } + .toSet() } - ui.miniMenuButtons = oldButtons ?: listOf( - MainActivity.DRAWER_ITEM_HOME, - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES, - MainActivity.DRAWER_ITEM_MESSAGES, - MainActivity.DRAWER_ITEM_HOMEWORK, - MainActivity.DRAWER_ITEM_SETTINGS + ui.miniMenuButtons = oldButtons ?: setOf( + NavTarget.HOME, + NavTarget.TIMETABLE, + NavTarget.AGENDA, + NavTarget.GRADES, + NavTarget.MESSAGES, + NavTarget.HOMEWORK, + NavTarget.SETTINGS ) dataVersion = 1 } @@ -81,9 +81,9 @@ class AppConfigMigrationV3(p: SharedPreferences, config: Config) { tokens?.forEach { val token = it.value.first when (it.key) { - LOGIN_TYPE_MOBIDZIENNIK -> sync.tokenMobidziennik = token - LOGIN_TYPE_VULCAN -> sync.tokenVulcan = token - LOGIN_TYPE_LIBRUS -> sync.tokenLibrus = token + LoginType.MOBIDZIENNIK.id -> sync.tokenMobidziennik = token + LoginType.VULCAN.id -> sync.tokenVulcan = token + LoginType.LIBRUS.id -> sync.tokenLibrus = token } } dataVersion = 2 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt index dcb4ab94..8a45bf63 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.BuildConfig import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.config.Config import pl.szczodrzynski.edziennik.ext.HOUR +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC import pl.szczodrzynski.edziennik.utils.models.Time import kotlin.math.abs @@ -32,14 +33,14 @@ class ConfigMigration(app: App, config: Config) { ui.appBackground = null ui.headerBackground = null ui.miniMenuVisible = false - ui.miniMenuButtons = listOf( - MainActivity.DRAWER_ITEM_HOME, - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES, - MainActivity.DRAWER_ITEM_MESSAGES, - MainActivity.DRAWER_ITEM_HOMEWORK, - MainActivity.DRAWER_ITEM_SETTINGS + ui.miniMenuButtons = setOf( + NavTarget.HOME, + NavTarget.TIMETABLE, + NavTarget.AGENDA, + NavTarget.GRADES, + NavTarget.MESSAGES, + NavTarget.HOMEWORK, + NavTarget.SETTINGS ) sync.enabled = true sync.interval = 1* HOUR.toInt() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt index 57177899..28e5f166 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt @@ -5,8 +5,8 @@ package pl.szczodrzynski.edziennik.config.utils import pl.szczodrzynski.edziennik.config.ProfileConfig -import pl.szczodrzynski.edziennik.data.db.entity.Notification import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType import pl.szczodrzynski.edziennik.ui.home.HomeCard import pl.szczodrzynski.edziennik.ui.home.HomeCardModel import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED @@ -31,7 +31,7 @@ class ProfileConfigMigration(config: ProfileConfig) { } if (dataVersion < 2) { - sync.notificationFilter = sync.notificationFilter + Notification.TYPE_TEACHER_ABSENCE + sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE dataVersion = 2 } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/EndpointChooser.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/EndpointChooser.kt index 7f882123..de834344 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/EndpointChooser.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/EndpointChooser.kt @@ -2,115 +2,116 @@ package pl.szczodrzynski.edziennik.data.api import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.api.models.Feature -import pl.szczodrzynski.edziennik.data.api.models.LoginMethod import pl.szczodrzynski.edziennik.data.db.entity.EndpointTimer import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_NEVER +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.ext.getFeatureTypesNecessary +import pl.szczodrzynski.edziennik.ext.getFeatureTypesUnnecessary +import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty -fun Data.prepare(loginMethods: List, features: List, featureIds: List, viewId: Int?, onlyEndpoints: List?) { - val data = this - - val possibleLoginMethods = data.loginMethods.toMutableList() - - for (loginMethod in loginMethods) { - if (loginMethod.isPossible(profile, loginStore)) - possibleLoginMethods += loginMethod.loginMethodId +fun Data.prepare( + features: List, + featureTypes: Set?, + onlyEndpoints: Set?, +) { + val loginType = this.loginStore.type + val possibleLoginMethods = this.loginMethods.toMutableList() + possibleLoginMethods += LoginMethod.values().filter { + it.loginType == loginType && it.isPossible?.invoke(profile, loginStore) != false } //var highestLoginMethod = 0 - var endpointList = mutableListOf() - val requiredLoginMethods = mutableListOf() + var possibleFeatures = mutableListOf() + val requiredLoginMethods = mutableListOf() - data.targetEndpointIds.clear() - data.targetLoginMethodIds.clear() + val syncFeatureTypes = when { + featureTypes.isNotNullNorEmpty() -> featureTypes!! + else -> getFeatureTypesUnnecessary() + } + getFeatureTypesNecessary() + val forceFeatureType = featureTypes?.singleOrNull() + + this.targetEndpoints.clear() + this.targetLoginMethods.clear() // get all endpoints for every feature, only if possible to login and possible/necessary to sync - for (featureId in featureIds) { - features.filter { - it.featureId == featureId // feature ID matches + for (featureId in syncFeatureTypes) { + possibleFeatures += features.filter { + it.featureType == featureId // feature ID matches && possibleLoginMethods.containsAll(it.requiredLoginMethods) // is possible to login - && it.shouldSync?.invoke(data) ?: true // is necessary/possible to sync - }.let { - endpointList.addAll(it) + && it.shouldSync?.invoke(this) ?: true // is necessary/possible to sync } } val timestamp = System.currentTimeMillis() - endpointList = endpointList - // sort the endpoint list by feature ID and priority - .sortedWith(compareBy(Feature::featureId, Feature::priority)) - // select only the most important endpoint for each feature - .distinctBy { it.featureId } - .toMutableList() - // add all endpoint IDs and required login methods, filtering using timers - .onEach { feature -> - feature.endpointIds.forEach { endpoint -> - if (onlyEndpoints?.contains(endpoint.first) == false) - return@forEach - (data.endpointTimers - .singleOrNull { it.endpointId == endpoint.first } ?: EndpointTimer(data.profile?.id - ?: -1, endpoint.first)) - .let { timer -> - if ( - onlyEndpoints?.contains(endpoint.first) == true || - timer.nextSync == SYNC_ALWAYS || - viewId != null && timer.viewId == viewId || - timer.nextSync != SYNC_NEVER && timer.nextSync < timestamp - ) { - data.targetEndpointIds[endpoint.first] = timer.lastSync - requiredLoginMethods.add(endpoint.second) - } - } - } + possibleFeatures = possibleFeatures + // sort the endpoint list by feature ID and priority + .sortedWith(compareBy(Feature::featureType, Feature::priority)) + // select only the most important endpoint for each feature + .distinctBy { it.featureType } + .toMutableList() + + for (feature in possibleFeatures) { + // add all endpoint IDs and required login methods, filtering using timers + feature.endpoints.forEach { endpoint -> + if (onlyEndpoints?.contains(endpoint.first) == false) + return@forEach + val timer = this.endpointTimers + .singleOrNull { it.endpointId == endpoint.first } + ?: EndpointTimer(this.profileId, endpoint.first) + if ( + onlyEndpoints?.contains(endpoint.first) == true || + timer.nextSync == SYNC_ALWAYS || + forceFeatureType != null && timer.featureType == forceFeatureType || + timer.nextSync != SYNC_NEVER && timer.nextSync < timestamp + ) { + this.targetEndpoints[endpoint.first] = timer.lastSync + requiredLoginMethods += endpoint.second } + } + } // check every login method for any dependencies - for (loginMethodId in requiredLoginMethods) { - var requiredLoginMethod: Int? = loginMethodId - while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) { - loginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { loginMethod -> - if (requiredLoginMethod != null) - data.targetLoginMethodIds.add(requiredLoginMethod!!) - requiredLoginMethod = loginMethod.requiredLoginMethod(data.profile, data.loginStore) - } + for (loginMethod in requiredLoginMethods) { + var requiredLoginMethod: LoginMethod? = loginMethod + while (requiredLoginMethod != null) { + this.targetLoginMethods += requiredLoginMethod + requiredLoginMethod = requiredLoginMethod.requiredLoginMethod?.invoke(this.profile, this.loginStore) } } // sort and distinct every login method and endpoint - data.targetLoginMethodIds = data.targetLoginMethodIds.toHashSet().toMutableList() - data.targetLoginMethodIds.sort() + this.targetLoginMethods = this.targetLoginMethods.toHashSet().toMutableList() + this.targetLoginMethods.sort() //data.targetEndpointIds = data.targetEndpointIds.toHashSet().toMutableList() //data.targetEndpointIds.sort() - progressCount = targetLoginMethodIds.size + targetEndpointIds.size + progressCount = targetLoginMethods.size + targetEndpoints.size progressStep = if (progressCount <= 0) 0f else 100f / progressCount.toFloat() } -fun Data.prepareFor(loginMethods: List, loginMethodId: Int) { +fun Data.prepareFor(loginMethod: LoginMethod) { + val loginType = loginStore.type val possibleLoginMethods = this.loginMethods.toMutableList() - - loginMethods.forEach { - if (it.isPossible(profile, loginStore)) - possibleLoginMethods += it.loginMethodId + possibleLoginMethods += LoginMethod.values().filter { + it.loginType == loginType && it.isPossible?.invoke(profile, loginStore) != false } - targetLoginMethodIds.clear() + this.targetLoginMethods.clear() // check the login method for any dependencies - var requiredLoginMethod: Int? = loginMethodId - while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) { - loginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { - if (requiredLoginMethod != null) - targetLoginMethodIds.add(requiredLoginMethod!!) - requiredLoginMethod = it.requiredLoginMethod(profile, loginStore) - } + var requiredLoginMethod: LoginMethod? = loginMethod + while (requiredLoginMethod != null) { + this.targetLoginMethods += requiredLoginMethod + requiredLoginMethod = requiredLoginMethod.requiredLoginMethod?.invoke(this.profile, this.loginStore) } // sort and distinct every login method - targetLoginMethodIds = targetLoginMethodIds.toHashSet().toMutableList() - targetLoginMethodIds.sort() + this.targetLoginMethods = this.targetLoginMethods.toHashSet().toMutableList() + this.targetLoginMethods.sort() progressCount = 0 progressStep = 0f diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Features.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Features.kt deleted file mode 100644 index e38b37b5..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Features.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2019-9-29. - */ - -package pl.szczodrzynski.edziennik.data.api - -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE -import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED -import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT - -internal const val FEATURE_TIMETABLE = 1 -internal const val FEATURE_AGENDA = 2 -internal const val FEATURE_GRADES = 3 -internal const val FEATURE_HOMEWORK = 4 -internal const val FEATURE_BEHAVIOUR = 5 -internal const val FEATURE_ATTENDANCE = 6 -internal const val FEATURE_MESSAGES_INBOX = 7 -internal const val FEATURE_MESSAGES_SENT = 8 -internal const val FEATURE_ANNOUNCEMENTS = 9 - -internal const val FEATURE_ALWAYS_NEEDED = 100 -internal const val FEATURE_STUDENT_INFO = 101 -internal const val FEATURE_STUDENT_NUMBER = 109 -internal const val FEATURE_SCHOOL_INFO = 102 -internal const val FEATURE_CLASS_INFO = 103 -internal const val FEATURE_TEAM_INFO = 104 -internal const val FEATURE_LUCKY_NUMBER = 105 -internal const val FEATURE_TEACHERS = 106 -internal const val FEATURE_SUBJECTS = 107 -internal const val FEATURE_CLASSROOMS = 108 -internal const val FEATURE_PUSH_CONFIG = 120 - -object Features { - private fun getAllNecessary(): List = listOf( - FEATURE_ALWAYS_NEEDED, - FEATURE_PUSH_CONFIG, - FEATURE_STUDENT_INFO, - FEATURE_STUDENT_NUMBER, - FEATURE_SCHOOL_INFO, - FEATURE_CLASS_INFO, - FEATURE_TEAM_INFO, - FEATURE_LUCKY_NUMBER, - FEATURE_TEACHERS, - FEATURE_SUBJECTS, - FEATURE_CLASSROOMS) - - private fun getAllFeatures(): List = listOf( - FEATURE_TIMETABLE, - FEATURE_AGENDA, - FEATURE_GRADES, - FEATURE_HOMEWORK, - FEATURE_BEHAVIOUR, - FEATURE_ATTENDANCE, - FEATURE_MESSAGES_INBOX, - FEATURE_MESSAGES_SENT, - FEATURE_ANNOUNCEMENTS) - - fun getAllIds(): List = getAllFeatures() + getAllNecessary() - - fun getIdsByView(targetId: Int, targetType: Int): List { - return (when (targetId) { - DRAWER_ITEM_HOME -> getAllFeatures() - DRAWER_ITEM_TIMETABLE -> listOf(FEATURE_TIMETABLE) - DRAWER_ITEM_AGENDA -> listOf(FEATURE_AGENDA) - DRAWER_ITEM_GRADES -> listOf(FEATURE_GRADES) - DRAWER_ITEM_MESSAGES -> when (targetType) { - TYPE_RECEIVED -> listOf(FEATURE_MESSAGES_INBOX) - TYPE_SENT -> listOf(FEATURE_MESSAGES_SENT) - else -> listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_SENT) - } - DRAWER_ITEM_HOMEWORK -> listOf(FEATURE_HOMEWORK) - DRAWER_ITEM_BEHAVIOUR -> listOf(FEATURE_BEHAVIOUR) - DRAWER_ITEM_ATTENDANCE -> listOf(FEATURE_ATTENDANCE) - DRAWER_ITEM_ANNOUNCEMENTS -> listOf(FEATURE_ANNOUNCEMENTS) - else -> getAllFeatures() - } + getAllNecessary()).sorted() - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt deleted file mode 100644 index 9825ea3f..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/LoginMethods.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2019-9-20. - */ - -package pl.szczodrzynski.edziennik.data.api - -import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginApi -import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginMessages -import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPortal -import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginSynergia -import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginApi2 -import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb -import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi -import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi -import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb -import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe -import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain -import pl.szczodrzynski.edziennik.data.api.models.LoginMethod - -// librus -// mobidziennik -// idziennik [*] -// vulcan -// mobireg - -const val SYNERGIA_API_ENABLED = false - -// the graveyard -const val LOGIN_TYPE_IDZIENNIK = 3 -const val LOGIN_TYPE_EDUDZIENNIK = 5 - -const val LOGIN_TYPE_TEMPLATE = 21 - -// LOGIN MODES -const val LOGIN_MODE_TEMPLATE_WEB = 0 - -// LOGIN METHODS -const val LOGIN_METHOD_NOT_NEEDED = -1 -const val LOGIN_METHOD_TEMPLATE_WEB = 100 -const val LOGIN_METHOD_TEMPLATE_API = 200 - -const val LOGIN_TYPE_LIBRUS = 2 -const val LOGIN_MODE_LIBRUS_EMAIL = 0 -const val LOGIN_MODE_LIBRUS_SYNERGIA = 1 -const val LOGIN_MODE_LIBRUS_JST = 2 -const val LOGIN_METHOD_LIBRUS_PORTAL = 100 -const val LOGIN_METHOD_LIBRUS_API = 200 -const val LOGIN_METHOD_LIBRUS_SYNERGIA = 300 -const val LOGIN_METHOD_LIBRUS_MESSAGES = 400 -val librusLoginMethods = listOf( - LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_PORTAL, LibrusLoginPortal::class.java) - .withIsPossible { _, loginStore -> - loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL - } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }, - - LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_API, LibrusLoginApi::class.java) - .withIsPossible { _, loginStore -> - loginStore.mode != LOGIN_MODE_LIBRUS_SYNERGIA || SYNERGIA_API_ENABLED - } - .withRequiredLoginMethod { _, loginStore -> - if (loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) LOGIN_METHOD_LIBRUS_PORTAL else LOGIN_METHOD_NOT_NEEDED - }, - - LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LibrusLoginSynergia::class.java) - .withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") } - .withRequiredLoginMethod { profile, _ -> - if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED - }, - - LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, LibrusLoginMessages::class.java) - .withIsPossible { _, loginStore -> !loginStore.hasLoginData("fakeLogin") } - .withRequiredLoginMethod { profile, _ -> - if (profile?.hasStudentData("accountPassword") == false || true) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED - } -) - -const val LOGIN_TYPE_MOBIDZIENNIK = 1 -const val LOGIN_MODE_MOBIDZIENNIK_WEB = 0 -const val LOGIN_METHOD_MOBIDZIENNIK_WEB = 100 -const val LOGIN_METHOD_MOBIDZIENNIK_API2 = 300 -val mobidziennikLoginMethods = listOf( - LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_WEB, MobidziennikLoginWeb::class.java) - .withIsPossible { _, _ -> true } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }, - - LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_API2, MobidziennikLoginApi2::class.java) - .withIsPossible { profile, _ -> profile?.getStudentData("email", null) != null } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } -) - -const val LOGIN_TYPE_VULCAN = 4 -const val LOGIN_MODE_VULCAN_API = 0 -const val LOGIN_MODE_VULCAN_WEB = 1 -const val LOGIN_MODE_VULCAN_HEBE = 2 -const val LOGIN_METHOD_VULCAN_WEB_MAIN = 100 -const val LOGIN_METHOD_VULCAN_WEB_NEW = 200 -const val LOGIN_METHOD_VULCAN_WEB_OLD = 300 -const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400 -const val LOGIN_METHOD_VULCAN_HEBE = 600 -val vulcanLoginMethods = listOf( - LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java) - .withIsPossible { _, loginStore -> loginStore.hasLoginData("webHost") } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }, - - /*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java) - .withIsPossible { _, _ -> false } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN }, - - LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_OLD, VulcanLoginWebOld::class.java) - .withIsPossible { _, _ -> false } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },*/ - - LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_HEBE, VulcanLoginHebe::class.java) - .withIsPossible { _, loginStore -> - loginStore.mode != LOGIN_MODE_VULCAN_API - } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } -) - -const val LOGIN_TYPE_PODLASIE = 6 -const val LOGIN_MODE_PODLASIE_API = 0 -const val LOGIN_METHOD_PODLASIE_API = 100 -val podlasieLoginMethods = listOf( - LoginMethod(LOGIN_TYPE_PODLASIE, LOGIN_METHOD_PODLASIE_API, PodlasieLoginApi::class.java) - .withIsPossible { _, _ -> true } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } -) - -const val LOGIN_TYPE_USOS = 7 -const val LOGIN_MODE_USOS_OAUTH = 0 -const val LOGIN_METHOD_USOS_API = 100 -val usosLoginMethods = listOf( - LoginMethod(LOGIN_TYPE_USOS, LOGIN_METHOD_USOS_API, UsosLoginApi::class.java) - .withIsPossible { _, _ -> true } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } -) - -val templateLoginMethods = listOf( - LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java) - .withIsPossible { _, _ -> true } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }, - - LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_API, TemplateLoginApi::class.java) - .withIsPossible { _, _ -> true } - .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_TEMPLATE_WEB } -) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt index 097ed29e..160db7e8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/EdziennikTask.kt @@ -6,8 +6,9 @@ package pl.szczodrzynski.edziennik.data.api.edziennik import com.google.gson.JsonObject import org.greenrobot.eventbus.EventBus -import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_ARCHIVED import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie @@ -22,6 +23,8 @@ import pl.szczodrzynski.edziennik.data.api.task.IApiTask import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -37,10 +40,10 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore)) fun sync() = EdziennikTask(-1, SyncRequest()) - fun syncProfile(profileId: Int, viewIds: List>? = null, onlyEndpoints: List? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments)) - fun syncProfileList(profileList: List) = EdziennikTask(-1, SyncProfileListRequest(profileList)) + fun syncProfile(profileId: Int, featureTypes: Set? = null, onlyEndpoints: Set? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(featureTypes, onlyEndpoints, arguments)) + fun syncProfileList(profileList: Set) = EdziennikTask(-1, SyncProfileListRequest(profileList)) fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message)) - fun messageSend(profileId: Int, recipients: List, subject: String, text: String) = EdziennikTask(profileId, MessageSendRequest(recipients, subject, text)) + fun messageSend(profileId: Int, recipients: Set, subject: String, text: String) = EdziennikTask(profileId, MessageSendRequest(recipients, subject, text)) fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest()) fun announcementGet(profileId: Int, announcement: AnnouncementFull) = EdziennikTask(profileId, AnnouncementGetRequest(announcement)) fun attachmentGet(profileId: Int, owner: Any, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(owner, attachmentId, attachmentName)) @@ -109,12 +112,12 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa } edziennikInterface = when (loginStore.type) { - LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback) - LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback) - LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback) - LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback) - LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback) - LOGIN_TYPE_USOS -> Usos(app, profile, loginStore, taskCallback) + LoginType.LIBRUS -> Librus(app, profile, loginStore, taskCallback) + LoginType.MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback) + LoginType.VULCAN -> Vulcan(app, profile, loginStore, taskCallback) + LoginType.PODLASIE -> Podlasie(app, profile, loginStore, taskCallback) + LoginType.TEMPLATE -> Template(app, profile, loginStore, taskCallback) + LoginType.USOS -> Usos(app, profile, loginStore, taskCallback) else -> null } if (edziennikInterface == null) { @@ -123,9 +126,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa when (request) { is SyncProfileRequest -> edziennikInterface?.sync( - featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } - ?: Features.getAllIds(), - viewId = request.viewIds?.get(0)?.first, + featureTypes = request.featureTypes, onlyEndpoints = request.onlyEndpoints, arguments = request.arguments) is MessageGetRequest -> edziennikInterface?.getMessage(request.message) @@ -150,10 +151,10 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa data class FirstLoginRequest(val loginStore: LoginStore) class SyncRequest - data class SyncProfileRequest(val viewIds: List>? = null, val onlyEndpoints: List? = null, val arguments: JsonObject? = null) - data class SyncProfileListRequest(val profileList: List) + data class SyncProfileRequest(val featureTypes: Set? = null, val onlyEndpoints: Set? = null, val arguments: JsonObject? = null) + data class SyncProfileListRequest(val profileList: Set) data class MessageGetRequest(val message: MessageFull) - data class MessageSendRequest(val recipients: List, val subject: String, val text: String) + data class MessageSendRequest(val recipients: Set, val subject: String, val text: String) class AnnouncementsReadRequest data class AnnouncementGetRequest(val announcement: AnnouncementFull) data class AttachmentGetRequest(val owner: Any, val attachmentId: Long, val attachmentName: String) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt index 27c61abc..ab898447 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt @@ -6,8 +6,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik import android.content.Intent import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.Intent import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.models.Date @@ -51,7 +51,7 @@ class ProfileArchiver(val app: App, val profile: Profile) { d(TAG, "New profile ID for ${profile.name}: ${profile.id}") when (profile.loginStoreType) { - LOGIN_TYPE_LIBRUS -> { + LoginType.LIBRUS -> { profile.removeStudentData("isPremium") profile.removeStudentData("pushDeviceId") profile.removeStudentData("startPointsSemester1") @@ -59,10 +59,8 @@ class ProfileArchiver(val app: App, val profile: Profile) { profile.removeStudentData("enablePointGrades") profile.removeStudentData("enableDescriptiveGrades") } - LOGIN_TYPE_MOBIDZIENNIK -> { - - } - LOGIN_TYPE_VULCAN -> { + LoginType.MOBIDZIENNIK -> {} + LoginType.VULCAN -> { // DataVulcan.isApiLoginValid() returns false so it will update the semester profile.removeStudentData("currentSemesterEndDate") profile.removeStudentData("studentSemesterId") @@ -71,15 +69,13 @@ class ProfileArchiver(val app: App, val profile: Profile) { profile.removeStudentData("semester2Id") profile.removeStudentData("studentClassId") } - LOGIN_TYPE_IDZIENNIK -> { + LoginType.IDZIENNIK -> { profile.removeStudentData("schoolYearId") } - LOGIN_TYPE_EDUDZIENNIK -> { - - } - LOGIN_TYPE_PODLASIE -> { - - } + LoginType.EDUDZIENNIK -> {} + LoginType.PODLASIE -> {} + LoginType.DEMO -> {} + LoginType.TEMPLATE -> {} } d(TAG, "Processed student data: ${profile.studentData}") diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt index 5d82191d..b5589832 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt @@ -5,13 +5,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_MESSAGES -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_PORTAL -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_SYNERGIA import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty @@ -25,15 +22,15 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app override fun satisfyLoginMethods() { loginMethods.clear() if (isPortalLoginValid()) - loginMethods += LOGIN_METHOD_LIBRUS_PORTAL + loginMethods += LoginMethod.LIBRUS_PORTAL if (isApiLoginValid()) - loginMethods += LOGIN_METHOD_LIBRUS_API + loginMethods += LoginMethod.LIBRUS_API if (isSynergiaLoginValid()) { - loginMethods += LOGIN_METHOD_LIBRUS_SYNERGIA + loginMethods += LoginMethod.LIBRUS_SYNERGIA app.cookieJar.set("synergia.librus.pl", "DZIENNIKSID", synergiaSessionId) } if (isMessagesLoginValid()) { - loginMethods += LOGIN_METHOD_LIBRUS_MESSAGES + loginMethods += LoginMethod.LIBRUS_MESSAGES app.cookieJar.set("wiadomosci.librus.pl", "DZIENNIKSID", messagesSessionId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt index 0830752f..5b29b9fe 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt @@ -24,6 +24,8 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -58,19 +60,19 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| __/ | |__*/ - override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) { + override fun sync(featureTypes: Set?, onlyEndpoints: Set?, arguments: JsonObject?) { data.arguments = arguments - data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId, onlyEndpoints) + data.prepare(LibrusFeatures, featureTypes, onlyEndpoints) login() } - private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) { - d(TAG, "Trying to login with ${data.targetLoginMethodIds}") + private fun login(loginMethod: LoginMethod? = null, afterLogin: (() -> Unit)? = null) { + d(TAG, "Trying to login with ${data.targetLoginMethods}") if (internalErrorList.isNotEmpty()) { d(TAG, " - Internal errors:") internalErrorList.forEach { d(TAG, " - code $it") } } - loginMethodId?.let { data.prepareFor(librusLoginMethods, it) } + loginMethod?.let { data.prepareFor(it) } afterLogin?.let { this.afterLogin = it } LibrusLogin(data) { data() @@ -78,7 +80,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } private fun data() { - d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + d(TAG, "Endpoint IDs: ${data.targetEndpoints}") if (internalErrorList.isNotEmpty()) { d(TAG, " - Internal errors:") internalErrorList.forEach { d(TAG, " - code $it") } @@ -89,14 +91,14 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun getMessage(message: MessageFull) { - login(LOGIN_METHOD_LIBRUS_MESSAGES) { + login(LoginMethod.LIBRUS_MESSAGES) { if (data.messagesLoginSuccessful) LibrusMessagesGetMessage(data, message) { completed() } else LibrusSynergiaGetMessage(data, message) { completed() } } } - override fun sendMessage(recipients: List, subject: String, text: String) { - login(LOGIN_METHOD_LIBRUS_MESSAGES) { + override fun sendMessage(recipients: Set, subject: String, text: String) { + login(LoginMethod.LIBRUS_MESSAGES) { LibrusMessagesSendMessage(data, recipients, subject, text) { completed() } @@ -104,7 +106,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun markAllAnnouncementsAsRead() { - login(LOGIN_METHOD_LIBRUS_SYNERGIA) { + login(LoginMethod.LIBRUS_SYNERGIA) { LibrusSynergiaMarkAllAnnouncementsAsRead(data) { completed() } @@ -112,7 +114,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun getAnnouncement(announcement: AnnouncementFull) { - login(LOGIN_METHOD_LIBRUS_API) { + login(LoginMethod.LIBRUS_API) { LibrusApiAnnouncementMarkAsRead(data, announcement) { completed() } @@ -122,13 +124,13 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) { when (owner) { is Message -> { - login(LOGIN_METHOD_LIBRUS_SYNERGIA) { + login(LoginMethod.LIBRUS_SYNERGIA) { if (data.messagesLoginSuccessful) LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) { completed() } LibrusSynergiaGetAttachment(data, owner, attachmentId, attachmentName) { completed() } } } is EventFull -> { - login(LOGIN_METHOD_LIBRUS_SYNERGIA) { + login(LoginMethod.LIBRUS_SYNERGIA) { LibrusSynergiaHomeworkGetAttachment(data, owner, attachmentId, attachmentName) { completed() } @@ -139,7 +141,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun getRecipientList() { - login(LOGIN_METHOD_LIBRUS_MESSAGES) { + login(LoginMethod.LIBRUS_MESSAGES) { LibrusMessagesGetRecipientList(data) { completed() } @@ -147,7 +149,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun getEvent(eventFull: EventFull) { - login(LOGIN_METHOD_LIBRUS_SYNERGIA) { + login(LoginMethod.LIBRUS_SYNERGIA) { LibrusSynergiaGetHomework(data, eventFull) { completed() } @@ -175,27 +177,27 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va internalErrorList.add(apiError.errorCode) when (apiError.errorCode) { ERROR_LIBRUS_PORTAL_ACCESS_DENIED -> { - data.loginMethods.remove(LOGIN_METHOD_LIBRUS_PORTAL) - data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_PORTAL) + data.loginMethods.remove(LoginMethod.LIBRUS_PORTAL) + data.prepareFor(LoginMethod.LIBRUS_PORTAL) data.portalTokenExpiryTime = 0 login() } ERROR_LIBRUS_API_ACCESS_DENIED, ERROR_LIBRUS_API_TOKEN_EXPIRED -> { - data.loginMethods.remove(LOGIN_METHOD_LIBRUS_API) - data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_API) + data.loginMethods.remove(LoginMethod.LIBRUS_API) + data.prepareFor(LoginMethod.LIBRUS_API) data.apiTokenExpiryTime = 0 login() } ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED -> { - data.loginMethods.remove(LOGIN_METHOD_LIBRUS_SYNERGIA) - data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_SYNERGIA) + data.loginMethods.remove(LoginMethod.LIBRUS_SYNERGIA) + data.prepareFor(LoginMethod.LIBRUS_SYNERGIA) data.synergiaSessionIdExpiryTime = 0 login() } ERROR_LIBRUS_MESSAGES_ACCESS_DENIED -> { - data.loginMethods.remove(LOGIN_METHOD_LIBRUS_MESSAGES) - data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_MESSAGES) + data.loginMethods.remove(LoginMethod.LIBRUS_MESSAGES) + data.prepareFor(LoginMethod.LIBRUS_MESSAGES) data.messagesSessionIdExpiryTime = 0 login() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/LibrusFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/LibrusFeatures.kt index c14a00df..eaa05b99 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/LibrusFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/LibrusFeatures.kt @@ -4,8 +4,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus -import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.Feature +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType const val ENDPOINT_LIBRUS_API_ME = 1001 const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002 @@ -58,14 +60,14 @@ const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030 val LibrusFeatures = listOf( - Feature(LOGIN_TYPE_LIBRUS, FEATURE_ALWAYS_NEEDED, listOf( - ENDPOINT_LIBRUS_API_LESSONS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.ALWAYS_NEEDED, listOf( + ENDPOINT_LIBRUS_API_LESSONS to LoginMethod.LIBRUS_API + )), // push config - Feature(LOGIN_TYPE_LIBRUS, FEATURE_PUSH_CONFIG, listOf( - ENDPOINT_LIBRUS_API_PUSH_CONFIG to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data -> + Feature(LoginType.LIBRUS, FeatureType.PUSH_CONFIG, listOf( + ENDPOINT_LIBRUS_API_PUSH_CONFIG to LoginMethod.LIBRUS_API + )).withShouldSync { data -> (data as DataLibrus).isPremium && !data.app.config.sync.tokenLibrusList.contains(data.profileId) }, @@ -76,72 +78,72 @@ val LibrusFeatures = listOf( /** * Timetable - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf( - ENDPOINT_LIBRUS_API_TIMETABLES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_SUBSTITUTIONS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.TIMETABLE, listOf( + ENDPOINT_LIBRUS_API_TIMETABLES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_SUBSTITUTIONS to LoginMethod.LIBRUS_API + )), /** * Agenda - using API. * Events, Parent-teacher meetings, free days (teacher/school/class). */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf( - ENDPOINT_LIBRUS_API_EVENTS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_EVENT_TYPES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_PT_MEETINGS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.AGENDA, listOf( + ENDPOINT_LIBRUS_API_EVENTS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_EVENT_TYPES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_PT_MEETINGS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS to LoginMethod.LIBRUS_API + )), /** * Grades - using API. * All grades + categories. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( - ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, + Feature(LoginType.LIBRUS, FeatureType.GRADES, listOf( + ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, // Commented out, because TextGrades/Categories is the same as Grades/Categories - /* ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, */ - ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_TEXT_GRADES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + /* ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, */ + ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_NORMAL_GRADES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_POINT_GRADES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_TEXT_GRADES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES to LoginMethod.LIBRUS_API + )), /** * Homework - using API. * Sync only if account has premium access. */ - /*Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf( - ENDPOINT_LIBRUS_API_HOMEWORK to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data -> + /*Feature(LoginType.LIBRUS, FeatureType.HOMEWORK, listOf( + ENDPOINT_LIBRUS_API_HOMEWORK to LoginMethod.LIBRUS_API + )).withShouldSync { data -> (data as DataLibrus).isPremium },*/ /** * Behaviour - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_BEHAVIOUR, listOf( - ENDPOINT_LIBRUS_API_NOTICES to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.BEHAVIOUR, listOf( + ENDPOINT_LIBRUS_API_NOTICES to LoginMethod.LIBRUS_API + )), /** * Attendance - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCE, listOf( - ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_ATTENDANCES to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.ATTENDANCE, listOf( + ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_ATTENDANCES to LoginMethod.LIBRUS_API + )), /** * Announcements - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf( - ENDPOINT_LIBRUS_API_ANNOUNCEMENTS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.ANNOUNCEMENTS, listOf( + ENDPOINT_LIBRUS_API_ANNOUNCEMENTS to LoginMethod.LIBRUS_API + )), @@ -150,99 +152,99 @@ val LibrusFeatures = listOf( /** * Student info - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( - ENDPOINT_LIBRUS_API_ME to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.STUDENT_INFO, listOf( + ENDPOINT_LIBRUS_API_ME to LoginMethod.LIBRUS_API + )), /** * School info - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf( - ENDPOINT_LIBRUS_API_SCHOOLS to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_UNITS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.SCHOOL_INFO, listOf( + ENDPOINT_LIBRUS_API_SCHOOLS to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_UNITS to LoginMethod.LIBRUS_API + )), /** * Class info - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf( - ENDPOINT_LIBRUS_API_CLASSES to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.CLASS_INFO, listOf( + ENDPOINT_LIBRUS_API_CLASSES to LoginMethod.LIBRUS_API + )), /** * Team info - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf( - ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.TEAM_INFO, listOf( + ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES to LoginMethod.LIBRUS_API + )), /** * Lucky number - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_LIBRUS_API_LUCKY_NUMBER to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data -> data.shouldSyncLuckyNumber() }, + Feature(LoginType.LIBRUS, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_LIBRUS_API_LUCKY_NUMBER to LoginMethod.LIBRUS_API + )).withShouldSync { data -> data.shouldSyncLuckyNumber() }, /** * Teacher list - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf( - ENDPOINT_LIBRUS_API_USERS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.TEACHERS, listOf( + ENDPOINT_LIBRUS_API_USERS to LoginMethod.LIBRUS_API + )), /** * Subject list - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf( - ENDPOINT_LIBRUS_API_SUBJECTS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.SUBJECTS, listOf( + ENDPOINT_LIBRUS_API_SUBJECTS to LoginMethod.LIBRUS_API + )), /** * Classroom list - using API. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf( - ENDPOINT_LIBRUS_API_CLASSROOMS to LOGIN_METHOD_LIBRUS_API - ), listOf(LOGIN_METHOD_LIBRUS_API)), + Feature(LoginType.LIBRUS, FeatureType.CLASSROOMS, listOf( + ENDPOINT_LIBRUS_API_CLASSROOMS to LoginMethod.LIBRUS_API + )), /** * Student info - using synergia scrapper. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( - ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA - ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)), + Feature(LoginType.LIBRUS, FeatureType.STUDENT_INFO, listOf( + ENDPOINT_LIBRUS_SYNERGIA_INFO to LoginMethod.LIBRUS_SYNERGIA + )), /** * Student number - using synergia scrapper. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf( - ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA - ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)), + Feature(LoginType.LIBRUS, FeatureType.STUDENT_NUMBER, listOf( + ENDPOINT_LIBRUS_SYNERGIA_INFO to LoginMethod.LIBRUS_SYNERGIA + )), /** * Grades - using API + synergia scrapper. */ - /*Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( - ENDPOINT_LIBRUS_API_NORMAL_GC to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API, - ENDPOINT_LIBRUS_SYNERGIA_GRADES to LOGIN_METHOD_LIBRUS_SYNERGIA - ), listOf(LOGIN_METHOD_LIBRUS_API, LOGIN_METHOD_LIBRUS_SYNERGIA)),*/ - /*Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( - ENDPOINT_LIBRUS_SYNERGIA_GRADES to LOGIN_METHOD_LIBRUS_SYNERGIA - ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),*/ + /*Feature(LoginType.LIBRUS, FeatureType.GRADES, listOf( + ENDPOINT_LIBRUS_API_NORMAL_GC to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_API_NORMAL_GRADES to LoginMethod.LIBRUS_API, + ENDPOINT_LIBRUS_SYNERGIA_GRADES to LoginMethod.LIBRUS_SYNERGIA + )),*/ + /*Endpoint(LoginType.LIBRUS, FeatureType.GRADES, listOf( + ENDPOINT_LIBRUS_SYNERGIA_GRADES to LoginMethod.LIBRUS_SYNERGIA + )),*/ /** * Homework - using scrapper. * Sync only if account has not premium access. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf( - ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK to LOGIN_METHOD_LIBRUS_SYNERGIA - ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA))/*.withShouldSync { data -> + Feature(LoginType.LIBRUS, FeatureType.HOMEWORK, listOf( + ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK to LoginMethod.LIBRUS_SYNERGIA + ))/*.withShouldSync { data -> !(data as DataLibrus).isPremium }*/, /** * Messages inbox - using messages website. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf( - ENDPOINT_LIBRUS_MESSAGES_RECEIVED to LOGIN_METHOD_LIBRUS_MESSAGES - ), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)), + Feature(LoginType.LIBRUS, FeatureType.MESSAGES_INBOX, listOf( + ENDPOINT_LIBRUS_MESSAGES_RECEIVED to LoginMethod.LIBRUS_MESSAGES + )), /** * Messages sent - using messages website. */ - Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_SENT, listOf( - ENDPOINT_LIBRUS_MESSAGES_SENT to LOGIN_METHOD_LIBRUS_MESSAGES - ), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)) + Feature(LoginType.LIBRUS, FeatureType.MESSAGES_SENT, listOf( + ENDPOINT_LIBRUS_MESSAGES_SENT to LoginMethod.LIBRUS_MESSAGES + )) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/LibrusData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/LibrusData.kt index db72ddcc..a5d9256e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/LibrusData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/LibrusData.kt @@ -24,7 +24,7 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) { } private fun nextEndpoint(onSuccess: () -> Unit) { - if (data.targetEndpointIds.isEmpty()) { + if (data.targetEndpoints.isEmpty()) { onSuccess() return } @@ -32,8 +32,8 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) { onSuccess() return } - val id = data.targetEndpointIds.firstKey() - val lastSync = data.targetEndpointIds.remove(id) + val id = data.targetEndpoints.firstKey() + val lastSync = data.targetEndpoints.remove(id) useEndpoint(id, lastSync) { endpointId -> data.progress(data.progressStep) nextEndpoint(onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncementMarkAsRead.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncementMarkAsRead.kt index 23cfceb4..8f45f9df 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncementMarkAsRead.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncementMarkAsRead.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus, @@ -34,7 +35,7 @@ class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus, data.setSeenMetadataList.add(Metadata( profileId, - Metadata.TYPE_ANNOUNCEMENT, + MetadataType.ANNOUNCEMENT, announcement.id, announcement.seen, announcement.notified diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncements.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncements.kt index fcf68cad..ad7c0df8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncements.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAnnouncements.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.db.entity.Announcement import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -54,7 +55,7 @@ class LibrusApiAnnouncements(override val data: DataLibrus, data.announcementList.add(announcementObject) data.setSeenMetadataList.add(Metadata( profileId, - Metadata.TYPE_ANNOUNCEMENT, + MetadataType.ANNOUNCEMENT, id, read, profile.empty || read diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAttendances.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAttendances.kt index 314a0716..b9bb6152 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAttendances.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiAttendances.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -76,7 +77,7 @@ class LibrusApiAttendances(override val data: DataLibrus, if(type?.baseType != Attendance.TYPE_PRESENT) { data.metadataList.add(Metadata( profileId, - Metadata.TYPE_ATTENDANCE, + MetadataType.ATTENDANCE, id, profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN, profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt index 7a528407..9d9e3015 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date import java.text.DecimalFormat @@ -63,7 +64,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus, data.gradeList.add(semester1StartGradeObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, semester1StartGradeObject.id, true, true @@ -91,7 +92,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus, data.gradeList.add(semester2StartGradeObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, semester2StartGradeObject.id, true, true @@ -165,7 +166,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus, data.gradeList.add(gradeObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt index 9b214d04..d77d1bf4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt @@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_TEXT import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -73,7 +74,7 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus, data.gradeList.add(gradeObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiEvents.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiEvents.kt index 82a0e267..79722a8b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiEvents.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiEvents.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -71,7 +72,7 @@ class LibrusApiEvents(override val data: DataLibrus, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_EVENT, + MetadataType.EVENT, id, profile?.empty ?: false, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGradeComments.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGradeComments.kt index 96225b67..0e9ea16c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGradeComments.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGradeComments.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api -import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt index 58621a0e..7c2d60f3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt @@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPO import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.models.Date @@ -97,7 +98,7 @@ class LibrusApiGrades(override val data: DataLibrus, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiHomework.kt index f304aaad..1c7741ce 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiHomework.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiHomework.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -51,7 +52,7 @@ class LibrusApiHomework(override val data: DataLibrus, data.eventList.add(eventObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_HOMEWORK, + MetadataType.HOMEWORK, id, profile?.empty ?: false, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLessons.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLessons.kt index 66075008..72605991 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLessons.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLessons.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api -import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_LESSONS import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLuckyNumber.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLuckyNumber.kt index 6ebe9e63..f93a06a3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLuckyNumber.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiLuckyNumber.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -47,7 +48,7 @@ class LibrusApiLuckyNumber(override val data: DataLibrus, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_LUCKY_NUMBER, + MetadataType.LUCKY_NUMBER, luckyNumberObject.date.value.toLong(), true, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiNotices.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiNotices.kt index ea61428e..754bbc03 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiNotices.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiNotices.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Notice import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -62,7 +63,7 @@ class LibrusApiNotices(override val data: DataLibrus, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_NOTICE, + MetadataType.NOTICE, id, profile?.empty ?: false, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt index 8a7ad29f..ee9fdfdf 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_AVG import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -66,7 +67,7 @@ class LibrusApiPointGrades(override val data: DataLibrus, data.gradeList.add(gradeObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPtMeetings.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPtMeetings.kt index 170c6135..35818ac0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPtMeetings.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPtMeetings.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -56,7 +57,7 @@ class LibrusApiPtMeetings(override val data: DataLibrus, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_EVENT, + MetadataType.EVENT, id, profile?.empty ?: false, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSchools.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSchools.kt index e42ab949..c5581e4d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSchools.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSchools.kt @@ -4,14 +4,12 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api -import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_SCHOOLS import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.db.entity.LessonRange import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Time -import java.util.* class LibrusApiSchools(override val data: DataLibrus, override val lastSync: Long?, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSubjects.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSubjects.kt index 17e30559..b615d379 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSubjects.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiSubjects.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api -import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_SUBJECTS import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTeacherFreeDays.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTeacherFreeDays.kt index 09ed5416..68053aeb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTeacherFreeDays.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTeacherFreeDays.kt @@ -5,13 +5,13 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api import androidx.core.util.isEmpty -import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsence +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -56,14 +56,14 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus, data.teacherAbsenceList.add(teacherAbsenceObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_TEACHER_ABSENCE, + MetadataType.TEACHER_ABSENCE, id, true, profile?.empty ?: false )) } - data.setSyncNext(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS, 6* HOUR, DRAWER_ITEM_AGENDA) + data.setSyncNext(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS, 6* HOUR, FeatureType.AGENDA) onSuccess(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt index bb19f11f..ce4cbcc2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_DESCRIPTIV import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -68,7 +69,7 @@ class LibrusApiTextGrades(override val data: DataLibrus, data.gradeList.add(gradeObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTimetables.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTimetables.kt index b224a381..ef19ab57 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTimetables.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTimetables.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.models.Date @@ -196,7 +197,7 @@ class LibrusApiTimetables(override val data: DataLibrus, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_LESSON_CHANGE, + MetadataType.LESSON_CHANGE, lessonObject.id, seen, seen diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetList.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetList.kt index 7d0cfeef..1535e759 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetList.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetList.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.data.api.ERROR_NOT_IMPLEMENTED import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_MESSAGES_RECEIVED @@ -12,6 +11,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_MESS import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.singleOrNull @@ -65,16 +66,17 @@ class LibrusMessagesGetList(override val data: DataLibrus, val recipientId = data.teacherList.singleOrNull { it.name == recipientFirstName && it.surname == recipientLastName - }?.id ?: { + }?.id ?: run { val teacherObject = Teacher( - profileId, - -1 * Utils.crc16("$recipientFirstName $recipientLastName".toByteArray()).toLong(), - recipientFirstName, - recipientLastName + profileId, + -1 * Utils.crc16("$recipientFirstName $recipientLastName".toByteArray()) + .toLong(), + recipientFirstName, + recipientLastName ) data.teacherList.put(teacherObject.id, teacherObject) teacherObject.id - }.invoke() + } val senderId = when (type) { TYPE_RECEIVED -> recipientId @@ -118,7 +120,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, data.messageRecipientList.add(messageRecipientObject) data.setSeenMetadataList.add(Metadata( profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, id, notified, notified @@ -127,7 +129,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, when (type) { TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS) - Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES) + Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, FeatureType.MESSAGES_SENT) } onSuccess(endpointId) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetMessage.kt index 8e6435c6..0e50467c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetMessage.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesGetMessage.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull import pl.szczodrzynski.edziennik.ext.fixName @@ -147,7 +148,7 @@ class LibrusMessagesGetMessage(override val data: DataLibrus, if (!messageObject.seen) { data.setSeenMetadataList.add(Metadata( messageObject.profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, messageObject.id, true, true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesSendMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesSendMessage.kt index 02248e99..bcd01311 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesSendMessage.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/messages/LibrusMessagesSendMessage.kt @@ -16,7 +16,7 @@ import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getString class LibrusMessagesSendMessage(override val data: DataLibrus, - val recipients: List, + val recipients: Set, val subject: String, val text: String, val onSuccess: () -> Unit diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessage.kt index b9df2af1..36cadfaa 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessage.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessage.kt @@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull import pl.szczodrzynski.edziennik.ext.get @@ -139,7 +140,7 @@ class LibrusSynergiaGetMessage(override val data: DataLibrus, if (!messageObject.seen) { data.setSeenMetadataList.add(Metadata( messageObject.profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, messageObject.id, true, true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessages.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessages.kt index 01cc69f6..626aec61 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessages.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaGetMessages.kt @@ -1,12 +1,13 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia import org.jsoup.Jsoup -import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.ERROR_NOT_IMPLEMENTED import pl.szczodrzynski.edziennik.data.api.Regexes import pl.szczodrzynski.edziennik.data.api.edziennik.librus.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia import pl.szczodrzynski.edziennik.data.db.entity.* +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.models.Date @@ -96,7 +97,7 @@ class LibrusSynergiaGetMessages(override val data: DataLibrus, data.messageRecipientList.add(messageRecipientObject) data.setSeenMetadataList.add(Metadata( profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, id, notified, notified @@ -105,7 +106,7 @@ class LibrusSynergiaGetMessages(override val data: DataLibrus, when (type) { Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS) - Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, MainActivity.DRAWER_ITEM_MESSAGES) + Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, FeatureType.MESSAGES_SENT) } onSuccess(endpointId) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaHomework.kt index ddf6635c..e5706613 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaHomework.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaHomework.kt @@ -5,7 +5,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia import org.jsoup.Jsoup -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK import pl.szczodrzynski.edziennik.data.api.POST import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK @@ -13,6 +12,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.HOUR import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.singleOrNull @@ -84,7 +85,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus, data.eventList.add(eventObject) data.metadataList.add(Metadata( profileId, - Metadata.TYPE_HOMEWORK, + MetadataType.HOMEWORK, id, seen, seen @@ -95,7 +96,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus, data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK)) // because this requires a synergia login (2 more requests!!!) sync this every few hours or if explicit :D - data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 5 * HOUR, DRAWER_ITEM_HOMEWORK) + data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 5 * HOUR, FeatureType.HOMEWORK) onSuccess(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK) } } ?: onSuccess(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaMarkAllAnnouncementsAsRead.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaMarkAllAnnouncementsAsRead.kt index 04a7f5b6..2cb06942 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaMarkAllAnnouncementsAsRead.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/synergia/LibrusSynergiaMarkAllAnnouncementsAsRead.kt @@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class LibrusSynergiaMarkAllAnnouncementsAsRead(override val data: DataLibrus, val onSuccess: () -> Unit @@ -17,7 +18,7 @@ class LibrusSynergiaMarkAllAnnouncementsAsRead(override val data: DataLibrus, init { synergiaGet(TAG, "ogloszenia") { - data.app.db.metadataDao().setAllSeen(profileId, Metadata.TYPE_ANNOUNCEMENT, true) + data.app.db.metadataDao().setAllSeen(profileId, MetadataType.ANNOUNCEMENT, true) onSuccess() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/firstlogin/LibrusFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/firstlogin/LibrusFirstLogin.kt index 43e5bda9..c29d3a85 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/firstlogin/LibrusFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/firstlogin/LibrusFirstLogin.kt @@ -11,6 +11,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPor import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.* class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) { @@ -23,11 +25,9 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) { private val profileList = mutableListOf() init { - val loginStoreId = data.loginStore.id - val loginStoreType = LOGIN_TYPE_LIBRUS - var firstProfileId = loginStoreId + var firstProfileId = data.loginStore.id - if (data.loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) { + if (data.loginStore.mode == LoginMode.LIBRUS_EMAIL) { // email login: use Portal for account list LibrusLoginPortal(data) { portal.portalGet(TAG, if (data.fakeLogin) FAKE_LIBRUS_ACCOUNTS else LIBRUS_ACCOUNTS_URL) { json, response -> @@ -66,8 +66,8 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) { val profile = Profile( firstProfileId++, - loginStoreId, - loginStoreType, + data.loginStore.id, + LoginType.LIBRUS, studentNameLong, data.portalEmail, studentNameLong, @@ -107,8 +107,8 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) { val profile = Profile( firstProfileId++, - loginStoreId, - loginStoreType, + data.loginStore.id, + LoginType.LIBRUS, studentNameLong, login, studentNameLong, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLogin.kt index c79acd2e..6af1398b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLogin.kt @@ -5,11 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.login import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_MESSAGES -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_PORTAL -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_SYNERGIA import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.utils.Utils class LibrusLogin(val data: DataLibrus, val onSuccess: () -> Unit) { @@ -24,7 +21,7 @@ class LibrusLogin(val data: DataLibrus, val onSuccess: () -> Unit) { } private fun nextLoginMethod(onSuccess: () -> Unit) { - if (data.targetLoginMethodIds.isEmpty()) { + if (data.targetLoginMethods.isEmpty()) { onSuccess() return } @@ -32,38 +29,39 @@ class LibrusLogin(val data: DataLibrus, val onSuccess: () -> Unit) { onSuccess() return } - useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + useLoginMethod(data.targetLoginMethods.removeAt(0)) { usedMethod -> data.progress(data.progressStep) - if (usedMethodId != -1) - data.loginMethods.add(usedMethodId) + if (usedMethod != null) + data.loginMethods.add(usedMethod) nextLoginMethod(onSuccess) } } - private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + private fun useLoginMethod(loginMethod: LoginMethod, onSuccess: (usedMethod: LoginMethod?) -> Unit) { // this should never be true - if (data.loginMethods.contains(loginMethodId)) { - onSuccess(-1) + if (data.loginMethods.contains(loginMethod)) { + onSuccess(null) return } - Utils.d(TAG, "Using login method $loginMethodId") - when (loginMethodId) { - LOGIN_METHOD_LIBRUS_PORTAL -> { + Utils.d(TAG, "Using login method $loginMethod") + when (loginMethod) { + LoginMethod.LIBRUS_PORTAL -> { data.startProgress(R.string.edziennik_progress_login_librus_portal) - LibrusLoginPortal(data) { onSuccess(loginMethodId) } + LibrusLoginPortal(data) { onSuccess(loginMethod) } } - LOGIN_METHOD_LIBRUS_API -> { + LoginMethod.LIBRUS_API -> { data.startProgress(R.string.edziennik_progress_login_librus_api) - LibrusLoginApi(data) { onSuccess(loginMethodId) } + LibrusLoginApi(data) { onSuccess(loginMethod) } } - LOGIN_METHOD_LIBRUS_SYNERGIA -> { + LoginMethod.LIBRUS_SYNERGIA -> { data.startProgress(R.string.edziennik_progress_login_librus_synergia) - LibrusLoginSynergia(data) { onSuccess(loginMethodId) } + LibrusLoginSynergia(data) { onSuccess(loginMethod) } } - LOGIN_METHOD_LIBRUS_MESSAGES -> { + LoginMethod.LIBRUS_MESSAGES -> { data.startProgress(R.string.edziennik_progress_login_librus_messages) - LibrusLoginMessages(data) { onSuccess(loginMethodId) } + LibrusLoginMessages(data) { onSuccess(loginMethod) } } + else -> {} } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginApi.kt index 58f7181d..d2ef2336 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginApi.kt @@ -12,6 +12,8 @@ import im.wangchao.mhttp.callback.JsonCallbackHandler import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.getUnixDate @@ -32,7 +34,7 @@ class LibrusLoginApi { this.data = data this.onSuccess = onSuccess - if (data.loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL && data.profile == null) { + if (data.loginStore.mode == LoginMode.LIBRUS_EMAIL && data.profile == null) { data.error(ApiError(TAG, ERROR_PROFILE_MISSING)) return } @@ -42,9 +44,9 @@ class LibrusLoginApi { } else { when (data.loginStore.mode) { - LOGIN_MODE_LIBRUS_EMAIL -> loginWithPortal() - LOGIN_MODE_LIBRUS_SYNERGIA -> loginWithSynergia() - LOGIN_MODE_LIBRUS_JST -> loginWithJst() + LoginMode.LIBRUS_EMAIL -> loginWithPortal() + LoginMode.LIBRUS_SYNERGIA -> loginWithSynergia() + LoginMode.LIBRUS_JST -> loginWithJst() else -> { data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE)) } @@ -53,7 +55,7 @@ class LibrusLoginApi { } private fun loginWithPortal() { - if (!data.loginMethods.contains(LOGIN_METHOD_LIBRUS_PORTAL)) { + if (!data.loginMethods.contains(LoginMethod.LIBRUS_PORTAL)) { data.error(ApiError(TAG, ERROR_LOGIN_METHOD_NOT_SATISFIED)) return } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginMessages.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginMessages.kt index 2a61f641..eeefe0f8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginMessages.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginMessages.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.LibrusRecaptchaHelper import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.getUnixDate import pl.szczodrzynski.edziennik.utils.Utils.d import java.io.StringWriter @@ -91,7 +92,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) { } else { data.app.cookieJar.clear("wiadomosci.librus.pl") - if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) { + if (data.loginMethods.contains(LoginMethod.LIBRUS_SYNERGIA)) { loginWithSynergia() } else if (data.apiLogin != null && data.apiPassword != null && false) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt index ab21c692..d4aa3859 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginPortal.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d import java.net.HttpURLConnection.* @@ -24,7 +25,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) { } init { run { - if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) { + if (data.loginStore.mode != LoginMode.LIBRUS_EMAIL) { data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE)) return@run } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginSynergia.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginSynergia.kt index a95af893..5f53890c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginSynergia.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/LibrusLoginSynergia.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.getUnixDate import pl.szczodrzynski.edziennik.utils.Utils.d @@ -34,7 +35,7 @@ class LibrusLoginSynergia(override val data: DataLibrus, val onSuccess: () -> Un } else { data.app.cookieJar.clear("synergia.librus.pl") - if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_API)) { + if (data.loginMethods.contains(LoginMethod.LIBRUS_API)) { loginWithApi() } else if (data.apiLogin != null && data.apiPassword != null && false) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/SynergiaTokenExtractor.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/SynergiaTokenExtractor.kt index 807bb131..7e1dc012 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/SynergiaTokenExtractor.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/login/SynergiaTokenExtractor.kt @@ -7,6 +7,7 @@ import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusPortal import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils.d @@ -16,7 +17,7 @@ class SynergiaTokenExtractor(override val data: DataLibrus, val onSuccess: () -> } init { run { - if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) { + if (data.loginStore.mode != LoginMode.LIBRUS_EMAIL) { data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE)) return@run } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/DataMobidziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/DataMobidziennik.kt index cee3cda5..493ef179 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/DataMobidziennik.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/DataMobidziennik.kt @@ -6,13 +6,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik import android.util.LongSparseArray import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_MOBIDZIENNIK_WEB -import pl.szczodrzynski.edziennik.data.api.Regexes import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.currentTimeUnix -import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -31,7 +29,7 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da override fun satisfyLoginMethods() { loginMethods.clear() if (isWebLoginValid()) { - loginMethods += LOGIN_METHOD_MOBIDZIENNIK_WEB + loginMethods += LoginMethod.MOBIDZIENNIK_WEB } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt index 0144ad5d..6d53a6c7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/Mobidziennik.kt @@ -18,6 +18,8 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -54,19 +56,19 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| __/ | |__*/ - override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) { + override fun sync(featureTypes: Set?, onlyEndpoints: Set?, arguments: JsonObject?) { data.arguments = arguments - data.prepare(mobidziennikLoginMethods, MobidziennikFeatures, featureIds, viewId, onlyEndpoints) + data.prepare(MobidziennikFeatures, featureTypes, onlyEndpoints) login() } - private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) { - d(TAG, "Trying to login with ${data.targetLoginMethodIds}") + private fun login(loginMethod: LoginMethod? = null, afterLogin: (() -> Unit)? = null) { + d(TAG, "Trying to login with ${data.targetLoginMethods}") if (internalErrorList.isNotEmpty()) { d(TAG, " - Internal errors:") internalErrorList.forEach { d(TAG, " - code $it") } } - loginMethodId?.let { data.prepareFor(mobidziennikLoginMethods, it) } + loginMethod?.let { data.prepareFor(it) } afterLogin?.let { this.afterLogin = it } MobidziennikLogin(data) { data() @@ -74,7 +76,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto } private fun data() { - d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + d(TAG, "Endpoint IDs: ${data.targetEndpoints}") if (internalErrorList.isNotEmpty()) { d(TAG, " - Internal errors:") internalErrorList.forEach { d(TAG, " - code $it") } @@ -85,15 +87,15 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto } override fun getMessage(message: MessageFull) { - login(LOGIN_METHOD_MOBIDZIENNIK_WEB) { + login(LoginMethod.MOBIDZIENNIK_WEB) { MobidziennikWebGetMessage(data, message) { completed() } } } - override fun sendMessage(recipients: List, subject: String, text: String) { - login(LOGIN_METHOD_MOBIDZIENNIK_WEB) { + override fun sendMessage(recipients: Set, subject: String, text: String) { + login(LoginMethod.MOBIDZIENNIK_WEB) { MobidziennikWebSendMessage(data, recipients, subject, text) { completed() } @@ -104,7 +106,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto override fun getAnnouncement(announcement: AnnouncementFull) {} override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) { - login(LOGIN_METHOD_MOBIDZIENNIK_WEB) { + login(LoginMethod.MOBIDZIENNIK_WEB) { MobidziennikWebGetAttachment(data, owner, attachmentId, attachmentName) { completed() } @@ -112,7 +114,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto } override fun getRecipientList() { - login(LOGIN_METHOD_MOBIDZIENNIK_WEB) { + login(LoginMethod.MOBIDZIENNIK_WEB) { MobidziennikWebGetRecipientList(data) { completed() } @@ -120,7 +122,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto } override fun getEvent(eventFull: EventFull) { - login(LOGIN_METHOD_MOBIDZIENNIK_WEB) { + login(LoginMethod.MOBIDZIENNIK_WEB) { if (eventFull.isHomework) { MobidziennikWebGetHomework(data, eventFull) { completed() @@ -158,8 +160,8 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE, ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID -> { - data.loginMethods.remove(LOGIN_METHOD_MOBIDZIENNIK_WEB) - data.prepareFor(mobidziennikLoginMethods, LOGIN_METHOD_MOBIDZIENNIK_WEB) + data.loginMethods.remove(LoginMethod.MOBIDZIENNIK_WEB) + data.prepareFor(LoginMethod.MOBIDZIENNIK_WEB) data.webSessionIdExpiryTime = 0 login() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt index 7b39e455..cd2c99ec 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt @@ -4,8 +4,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik -import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.Feature +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType const val ENDPOINT_MOBIDZIENNIK_API_MAIN = 1000 const val ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX = 2011 @@ -23,15 +25,15 @@ const val ENDPOINT_MOBIDZIENNIK_API2_MAIN = 3000 val MobidziennikFeatures = listOf( // always synced - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_ALWAYS_NEEDED, listOf( - ENDPOINT_MOBIDZIENNIK_API_MAIN to LOGIN_METHOD_MOBIDZIENNIK_WEB, - ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), // TODO divide features into separate view IDs (all with API_MAIN) + Feature(LoginType.MOBIDZIENNIK, FeatureType.ALWAYS_NEEDED, listOf( + ENDPOINT_MOBIDZIENNIK_API_MAIN to LoginMethod.MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL to LoginMethod.MOBIDZIENNIK_WEB + )), // TODO divide features into separate view IDs (all with API_MAIN) // push config - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_PUSH_CONFIG, listOf( - ENDPOINT_MOBIDZIENNIK_API2_MAIN to LOGIN_METHOD_MOBIDZIENNIK_API2 - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_API2)).withShouldSync { data -> + Feature(LoginType.MOBIDZIENNIK, FeatureType.PUSH_CONFIG, listOf( + ENDPOINT_MOBIDZIENNIK_API2_MAIN to LoginMethod.MOBIDZIENNIK_API2 + )).withShouldSync { data -> !data.app.config.sync.tokenMobidziennikList.contains(data.profileId) }, @@ -42,36 +44,36 @@ val MobidziennikFeatures = listOf( /** * Timetable - web scraping - does nothing if the API_MAIN timetable is enough. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_TIMETABLE, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LoginType.MOBIDZIENNIK, FeatureType.TIMETABLE, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE to LoginMethod.MOBIDZIENNIK_WEB + )), /** * Agenda - "API" + web scraping. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_AGENDA, listOf( - ENDPOINT_MOBIDZIENNIK_API_MAIN to LOGIN_METHOD_MOBIDZIENNIK_WEB, - ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LoginType.MOBIDZIENNIK, FeatureType.AGENDA, listOf( + ENDPOINT_MOBIDZIENNIK_API_MAIN to LoginMethod.MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR to LoginMethod.MOBIDZIENNIK_WEB + )), /** * Grades - "API" + web scraping. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_GRADES, listOf( - ENDPOINT_MOBIDZIENNIK_API_MAIN to LOGIN_METHOD_MOBIDZIENNIK_WEB, - ENDPOINT_MOBIDZIENNIK_WEB_GRADES to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LoginType.MOBIDZIENNIK, FeatureType.GRADES, listOf( + ENDPOINT_MOBIDZIENNIK_API_MAIN to LoginMethod.MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_GRADES to LoginMethod.MOBIDZIENNIK_WEB + )), /** * Behaviour - "API" + web scraping. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_BEHAVIOUR, listOf( - ENDPOINT_MOBIDZIENNIK_API_MAIN to LOGIN_METHOD_MOBIDZIENNIK_WEB, - ENDPOINT_MOBIDZIENNIK_WEB_NOTICES to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LoginType.MOBIDZIENNIK, FeatureType.BEHAVIOUR, listOf( + ENDPOINT_MOBIDZIENNIK_API_MAIN to LoginMethod.MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_NOTICES to LoginMethod.MOBIDZIENNIK_WEB + )), /** * Attendance - only web scraping. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_ATTENDANCE, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LoginType.MOBIDZIENNIK, FeatureType.ATTENDANCE, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE to LoginMethod.MOBIDZIENNIK_WEB + )), @@ -80,38 +82,38 @@ val MobidziennikFeatures = listOf( /** * Messages inbox - using web scraper. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_MESSAGES_INBOX, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX to LOGIN_METHOD_MOBIDZIENNIK_WEB, - ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LoginType.MOBIDZIENNIK, FeatureType.MESSAGES_INBOX, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX to LoginMethod.MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL to LoginMethod.MOBIDZIENNIK_WEB + )), /** * Messages sent - using web scraper. */ - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_MESSAGES_SENT, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT to LOGIN_METHOD_MOBIDZIENNIK_WEB, - ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)) + Feature(LoginType.MOBIDZIENNIK, FeatureType.MESSAGES_SENT, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT to LoginMethod.MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL to LoginMethod.MOBIDZIENNIK_WEB + )) // lucky number possibilities // all endpoints that may supply the lucky number - /*Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_MANUALS to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 10 }, + /*Feature(LoginType.MOBIDZIENNIK, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_MANUALS to LoginMethod.MOBIDZIENNIK_WEB + )).apply { priority = 10 }, - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 3 }, + Feature(LoginType.MOBIDZIENNIK, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR to LoginMethod.MOBIDZIENNIK_WEB + )).apply { priority = 3 }, - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_GRADES to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 2 }, + Feature(LoginType.MOBIDZIENNIK, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_GRADES to LoginMethod.MOBIDZIENNIK_WEB + )).apply { priority = 2 }, - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_NOTICES to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 1 }, + Feature(LoginType.MOBIDZIENNIK, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_NOTICES to LoginMethod.MOBIDZIENNIK_WEB + )).apply { priority = 1 }, - Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_MOBIDZIENNIK_WEB - ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 4 }*/ + Feature(LoginType.MOBIDZIENNIK, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE to LoginMethod.MOBIDZIENNIK_WEB + )).apply { priority = 4 }*/ ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt index b82f6355..4b58d203 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt @@ -21,7 +21,7 @@ class MobidziennikData(val data: DataMobidziennik, val onSuccess: () -> Unit) { } private fun nextEndpoint(onSuccess: () -> Unit) { - if (data.targetEndpointIds.isEmpty()) { + if (data.targetEndpoints.isEmpty()) { onSuccess() return } @@ -29,8 +29,8 @@ class MobidziennikData(val data: DataMobidziennik, val onSuccess: () -> Unit) { onSuccess() return } - val id = data.targetEndpointIds.firstKey() - val lastSync = data.targetEndpointIds.remove(id) + val id = data.targetEndpoints.firstKey() + val lastSync = data.targetEndpoints.remove(id) useEndpoint(id, lastSync) { endpointId -> data.progress(data.progressStep) nextEndpoint(onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiAttendance.kt index 473b3691..054b2fc7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiAttendance.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiAttendance.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSEN import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List) { init { run { @@ -70,7 +71,7 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List) data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_ATTENDANCE, + MetadataType.ATTENDANCE, id, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiEvents.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiEvents.kt index 7a72d3de..d8d9d7c7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiEvents.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiEvents.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidzienn import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time import java.text.ParseException @@ -68,7 +69,7 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_EVENT, + MetadataType.EVENT, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt index c3c1b449..91ddedf0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt @@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class MobidziennikApiGrades(val data: DataMobidziennik, rows: List) { init { data.profile?.also { profile -> run { @@ -91,7 +92,7 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiHomework.kt index a79eaded..52f7cdc4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiHomework.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiHomework.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidzienn import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.utils.html.BetterHtml import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -47,7 +48,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_HOMEWORK, + MetadataType.HOMEWORK, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiNotices.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiNotices.kt index 66bfe1fd..c765e1ec 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiNotices.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiNotices.kt @@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Notice +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.utils.models.Date class MobidziennikApiNotices(val data: DataMobidziennik, rows: List) { @@ -48,7 +49,7 @@ class MobidziennikApiNotices(val data: DataMobidziennik, rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_NOTICE, + MetadataType.NOTICE, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiTimetable.kt index 8e490832..9df9cc01 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiTimetable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiTimetable.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.LessonRange import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.keys import pl.szczodrzynski.edziennik.ext.singleOrNull @@ -94,7 +95,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_LESSON_CHANGE, + MetadataType.LESSON_CHANGE, it.id, seen, seen diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikLuckyNumberExtractor.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikLuckyNumberExtractor.kt index ece23d7f..2ad8a61f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikLuckyNumberExtractor.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikLuckyNumberExtractor.kt @@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.data.api.Regexes import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.utils.models.Date class MobidziennikLuckyNumberExtractor(val data: DataMobidziennik, text: String) { @@ -26,7 +27,7 @@ class MobidziennikLuckyNumberExtractor(val data: DataMobidziennik, text: String) data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_LUCKY_NUMBER, + MetadataType.LUCKY_NUMBER, luckyNumberObject.date.value.toLong(), true, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAttendance.kt index 9160e4d6..28371b18 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAttendance.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAttendance.kt @@ -20,6 +20,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEA import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.singleOrNull @@ -246,7 +247,7 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik, data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_ATTENDANCE, + MetadataType.ATTENDANCE, id, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebCalendar.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebCalendar.kt index b6a10335..11cfa69d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebCalendar.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebCalendar.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.Mobidzien import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.utils.Utils.crc16 import pl.szczodrzynski.edziennik.utils.models.Date @@ -86,7 +87,7 @@ class MobidziennikWebCalendar(override val data: DataMobidziennik, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_EVENT, + MetadataType.EVENT, eventObject.id, profile?.empty ?: false, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGetMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGetMessage.kt index 3e196ec0..23650982 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGetMessage.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGetMessage.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidzienn import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull import pl.szczodrzynski.edziennik.ext.fixName @@ -133,7 +134,7 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik, if (!message.seen) { // TODO discover why this monstrosity instead of MetadataDao.setSeen data.setSeenMetadataList.add(Metadata( message.profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, message.id, true, true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt index 285441b6..ef6bb826 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.fixWhiteSpaces import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.singleOrNull @@ -135,7 +136,7 @@ class MobidziennikWebGrades(override val data: DataMobidziennik, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, gradeObject.id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesAll.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesAll.kt index aebff41e..99715831 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesAll.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesAll.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.singleOrNull @@ -84,7 +85,7 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik, ) data.messageList.add(message) - data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true)) + data.metadataList.add(Metadata(profileId, MetadataType.MESSAGE, message.id, true, true)) } // sync every 7 days as we probably don't expect more than diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesInbox.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesInbox.kt index b3819784..698f125f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesInbox.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesInbox.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.singleOrNull import pl.szczodrzynski.edziennik.utils.models.Date @@ -83,7 +84,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik, data.setSeenMetadataList.add( Metadata( profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, message.id, isRead, isRead || profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesSent.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesSent.kt index 7f249cf6..2e15751c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesSent.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebMessagesSent.kt @@ -5,7 +5,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web import org.jsoup.Jsoup -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.data.api.Regexes import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT @@ -14,6 +13,8 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.get @@ -100,14 +101,14 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik, data.setSeenMetadataList.add( Metadata( profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, message.id, true, true )) } - data.setSyncNext(ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT, 1* DAY, DRAWER_ITEM_MESSAGES) + data.setSyncNext(ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT, 1* DAY, FeatureType.MESSAGES_SENT) onSuccess(ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebSendMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebSendMessage.kt index b5a6c5ee..d4965b36 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebSendMessage.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebSendMessage.kt @@ -11,9 +11,10 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.Mobidzien import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class MobidziennikWebSendMessage(override val data: DataMobidziennik, - val recipients: List, + val recipients: Set, val subject: String, val text: String, val onSuccess: () -> Unit @@ -43,7 +44,7 @@ class MobidziennikWebSendMessage(override val data: DataMobidziennik, // TODO create MobidziennikWebMessagesSent and replace this MobidziennikWebMessagesAll(data, null) { val message = data.messageList.firstOrNull { it.isSent && it.subject == subject } - val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } + val metadata = data.metadataList.firstOrNull { it.thingType == MetadataType.MESSAGE && it.thingId == message?.id } val event = MessageSentEvent(data.profileId, message, message?.addedDate) EventBus.getDefault().postSticky(event) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt index dd0ff03f..ce693c58 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt @@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel.Timetable.Comp import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.MS import pl.szczodrzynski.edziennik.ext.get @@ -343,7 +344,7 @@ class MobidziennikWebTimetable( data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_LESSON_CHANGE, + MetadataType.LESSON_CHANGE, it.id, seen, seen diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/firstlogin/MobidziennikFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/firstlogin/MobidziennikFirstLogin.kt index 91390c5c..f1e67115 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/firstlogin/MobidziennikFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/firstlogin/MobidziennikFirstLogin.kt @@ -1,12 +1,12 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin import org.greenrobot.eventbus.EventBus -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.set import pl.szczodrzynski.edziennik.utils.models.Date @@ -20,9 +20,7 @@ class MobidziennikFirstLogin(val data: DataMobidziennik, val onSuccess: () -> Un private val profileList = mutableListOf() init { - val loginStoreId = data.loginStore.id - val loginStoreType = LOGIN_TYPE_MOBIDZIENNIK - var firstProfileId = loginStoreId + var firstProfileId = data.loginStore.id MobidziennikLoginWeb(data) { web.webGet(TAG, "/api/zrzutbazy") { text -> @@ -66,8 +64,8 @@ class MobidziennikFirstLogin(val data: DataMobidziennik, val onSuccess: () -> Un val profile = Profile( firstProfileId++, - loginStoreId, - loginStoreType, + data.loginStore.id, + LoginType.MOBIDZIENNIK, studentNameLong, data.loginUsername, studentNameLong, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLogin.kt index 7bc79a7b..308087fb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLogin.kt @@ -5,9 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_MOBIDZIENNIK_API2 -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_MOBIDZIENNIK_WEB import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.utils.Utils class MobidziennikLogin(val data: DataMobidziennik, val onSuccess: () -> Unit) { @@ -22,7 +21,7 @@ class MobidziennikLogin(val data: DataMobidziennik, val onSuccess: () -> Unit) { } private fun nextLoginMethod(onSuccess: () -> Unit) { - if (data.targetLoginMethodIds.isEmpty()) { + if (data.targetLoginMethods.isEmpty()) { onSuccess() return } @@ -30,30 +29,31 @@ class MobidziennikLogin(val data: DataMobidziennik, val onSuccess: () -> Unit) { onSuccess() return } - useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + useLoginMethod(data.targetLoginMethods.removeAt(0)) { usedMethod -> data.progress(data.progressStep) - if (usedMethodId != -1) - data.loginMethods.add(usedMethodId) + if (usedMethod != null) + data.loginMethods.add(usedMethod) nextLoginMethod(onSuccess) } } - private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + private fun useLoginMethod(loginMethod: LoginMethod, onSuccess: (usedMethod: LoginMethod?) -> Unit) { // this should never be true - if (data.loginMethods.contains(loginMethodId)) { - onSuccess(-1) + if (data.loginMethods.contains(loginMethod)) { + onSuccess(null) return } - Utils.d(TAG, "Using login method $loginMethodId") - when (loginMethodId) { - LOGIN_METHOD_MOBIDZIENNIK_WEB -> { + Utils.d(TAG, "Using login method $loginMethod") + when (loginMethod) { + LoginMethod.MOBIDZIENNIK_WEB -> { data.startProgress(R.string.edziennik_progress_login_mobidziennik_web) - MobidziennikLoginWeb(data) { onSuccess(loginMethodId) } + MobidziennikLoginWeb(data) { onSuccess(loginMethod) } } - LOGIN_METHOD_MOBIDZIENNIK_API2 -> { + LoginMethod.MOBIDZIENNIK_API2 -> { data.startProgress(R.string.edziennik_progress_login_mobidziennik_api2) - MobidziennikLoginApi2(data) { onSuccess(loginMethodId) } + MobidziennikLoginApi2(data) { onSuccess(loginMethod) } } + else -> {} } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt index 0a5cce84..52b05a20 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt @@ -5,10 +5,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.crc32 import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty @@ -19,7 +19,7 @@ class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(a override fun satisfyLoginMethods() { loginMethods.clear() if (isApiLoginValid()) - loginMethods += LOGIN_METHOD_PODLASIE_API + loginMethods += LoginMethod.PODLASIE_API } override fun generateUserCode(): String = "$schoolShortName:$loginShort:${studentId?.crc32()}" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt index 0eaaebae..660ba2e9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/Podlasie.kt @@ -16,11 +16,11 @@ import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError -import pl.szczodrzynski.edziennik.data.api.podlasieLoginMethods import pl.szczodrzynski.edziennik.data.api.prepare import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -55,11 +55,11 @@ class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore, |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| __/ | |__*/ - override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) { + override fun sync(featureTypes: Set?, onlyEndpoints: Set?, arguments: JsonObject?) { data.arguments = arguments - data.prepare(podlasieLoginMethods, PodlasieFeatures, featureIds, viewId, onlyEndpoints) - Utils.d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}") - Utils.d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + data.prepare(PodlasieFeatures, featureTypes, onlyEndpoints) + Utils.d(TAG, "LoginMethod IDs: ${data.targetLoginMethods}") + Utils.d(TAG, "Endpoint IDs: ${data.targetEndpoints}") PodlasieLogin(data) { PodlasieData(data) { completed() @@ -71,7 +71,7 @@ class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore, } - override fun sendMessage(recipients: List, subject: String, text: String) { + override fun sendMessage(recipients: Set, subject: String, text: String) { } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/PodlasieFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/PodlasieFeatures.kt index 82c6f659..6d131990 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/PodlasieFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/PodlasieFeatures.kt @@ -4,15 +4,15 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie -import pl.szczodrzynski.edziennik.data.api.FEATURE_ALWAYS_NEEDED -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_PODLASIE import pl.szczodrzynski.edziennik.data.api.models.Feature +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType const val ENDPOINT_PODLASIE_API_MAIN = 1001 val PodlasieFeatures = listOf( - Feature(LOGIN_TYPE_PODLASIE, FEATURE_ALWAYS_NEEDED, listOf( - ENDPOINT_PODLASIE_API_MAIN to LOGIN_METHOD_PODLASIE_API - ), listOf(LOGIN_METHOD_PODLASIE_API)) + Feature(LoginType.PODLASIE, FeatureType.ALWAYS_NEEDED, listOf( + ENDPOINT_PODLASIE_API_MAIN to LoginMethod.PODLASIE_API + )) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieData.kt index ce1197b8..f1117537 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/PodlasieData.kt @@ -20,7 +20,7 @@ class PodlasieData(val data: DataPodlasie, val onSuccess: () -> Unit) { } private fun nextEndpoint(onSuccess: () -> Unit) { - if (data.targetEndpointIds.isEmpty()) { + if (data.targetEndpoints.isEmpty()) { onSuccess() return } @@ -28,8 +28,8 @@ class PodlasieData(val data: DataPodlasie, val onSuccess: () -> Unit) { onSuccess() return } - val id = data.targetEndpointIds.firstKey() - val lastSync = data.targetEndpointIds.remove(id) + val id = data.targetEndpoints.firstKey() + val lastSync = data.targetEndpoints.remove(id) useEndpoint(id, lastSync) { data.progress(data.progressStep) nextEndpoint(onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiEvents.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiEvents.kt index f51c7477..25735d3d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiEvents.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiEvents.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.utils.models.Date @@ -64,7 +65,7 @@ class PodlasieApiEvents(val data: DataPodlasie, val rows: List) { data.metadataList.add( Metadata( data.profileId, - if (type == Event.TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT, + if (type == Event.TYPE_HOMEWORK) MetadataType.HOMEWORK else MetadataType.EVENT, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt index 94dadfc8..15a3499f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt @@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getString @@ -62,7 +63,7 @@ class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List) data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile.empty, profile.empty @@ -99,7 +100,7 @@ class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List) data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, proposedGradeObject.id, profile.empty, profile.empty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt index 4aa749ef..9a049313 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getFloat import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getLong @@ -60,7 +61,7 @@ class PodlasieApiGrades(val data: DataPodlasie, val rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiHomework.kt index be2fd062..8a8e851b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiHomework.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiHomework.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.crc32 import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.getString @@ -53,7 +54,7 @@ class PodlasieApiHomework(val data: DataPodlasie, val rows: List) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_HOMEWORK, + MetadataType.HOMEWORK, id, data.profile?.empty ?: false, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiLuckyNumber.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiLuckyNumber.kt index 725ec727..87b8dcc8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiLuckyNumber.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiLuckyNumber.kt @@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.utils.models.Date class PodlasieApiLuckyNumber(val data: DataPodlasie, val luckyNumber: Int) { @@ -21,7 +22,7 @@ class PodlasieApiLuckyNumber(val data: DataPodlasie, val luckyNumber: Int) { data.metadataList.add( Metadata( data.profileId, - Metadata.TYPE_LUCKY_NUMBER, + MetadataType.LUCKY_NUMBER, luckyNumberObject.date.value.toLong(), true, data.profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/firstlogin/PodlasieFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/firstlogin/PodlasieFirstLogin.kt index a99ea2ee..3b978cae 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/firstlogin/PodlasieFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/firstlogin/PodlasieFirstLogin.kt @@ -5,7 +5,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin import org.greenrobot.eventbus.EventBus -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_PODLASIE import pl.szczodrzynski.edziennik.data.api.PODLASIE_API_LOGOUT_DEVICES_ENDPOINT import pl.szczodrzynski.edziennik.data.api.PODLASIE_API_USER_ENDPOINT import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie @@ -13,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieApi import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.getShortName import pl.szczodrzynski.edziennik.ext.getString @@ -32,9 +32,6 @@ class PodlasieFirstLogin(val data: DataPodlasie, val onSuccess: () -> Unit) { } private fun doLogin() { - val loginStoreId = data.loginStore.id - val loginStoreType = LOGIN_TYPE_PODLASIE - if (data.loginStore.getLoginData("logoutDevices", false)) { data.loginStore.removeLoginData("logoutDevices") api.apiGet(TAG, PODLASIE_API_LOGOUT_DEVICES_ENDPOINT) { @@ -57,9 +54,9 @@ class PodlasieFirstLogin(val data: DataPodlasie, val onSuccess: () -> Unit) { val apiUrl = json.getString("URL") val profile = Profile( - loginStoreId, - loginStoreId, - loginStoreType, + data.loginStore.id, + data.loginStore.id, + LoginType.PODLASIE, studentNameLong, login, studentNameLong, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/login/PodlasieLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/login/PodlasieLogin.kt index 406bb997..73594d41 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/login/PodlasieLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/login/PodlasieLogin.kt @@ -5,8 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.utils.Utils class PodlasieLogin(val data: DataPodlasie, val onSuccess: () -> Unit) { @@ -21,7 +21,7 @@ class PodlasieLogin(val data: DataPodlasie, val onSuccess: () -> Unit) { } private fun nextLoginMethod(onSuccess: () -> Unit) { - if (data.targetLoginMethodIds.isEmpty()) { + if (data.targetLoginMethods.isEmpty()) { onSuccess() return } @@ -29,26 +29,27 @@ class PodlasieLogin(val data: DataPodlasie, val onSuccess: () -> Unit) { onSuccess() return } - useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + useLoginMethod(data.targetLoginMethods.removeAt(0)) { usedMethod -> data.progress(data.progressStep) - if (usedMethodId != -1) - data.loginMethods.add(usedMethodId) + if (usedMethod != null) + data.loginMethods.add(usedMethod) nextLoginMethod(onSuccess) } } - private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + private fun useLoginMethod(loginMethod: LoginMethod, onSuccess: (usedMethod: LoginMethod?) -> Unit) { // this should never be true - if (data.loginMethods.contains(loginMethodId)) { - onSuccess(-1) + if (data.loginMethods.contains(loginMethod)) { + onSuccess(null) return } - Utils.d(TAG, "Using login method $loginMethodId") - when (loginMethodId) { - LOGIN_METHOD_PODLASIE_API -> { + Utils.d(TAG, "Using login method $loginMethod") + when (loginMethod) { + LoginMethod.PODLASIE_API -> { data.startProgress(R.string.edziennik_progress_login_podlasie_api) - PodlasieLoginApi(data) { onSuccess(loginMethodId) } + PodlasieLoginApi(data) { onSuccess(loginMethod) } } + else -> {} } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/DataTemplate.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/DataTemplate.kt index 17644978..9d8c5f53 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/DataTemplate.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/DataTemplate.kt @@ -5,11 +5,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_TEMPLATE_API -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_TEMPLATE_WEB import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty @@ -26,11 +25,11 @@ class DataTemplate(app: App, profile: Profile?, loginStore: LoginStore) : Data(a override fun satisfyLoginMethods() { loginMethods.clear() if (isWebLoginValid()) { - loginMethods += LOGIN_METHOD_TEMPLATE_WEB + loginMethods += LoginMethod.TEMPLATE_WEB app.cookieJar.set("eregister.example.com", "AuthCookie", webCookie) } if (isApiLoginValid()) - loginMethods += LOGIN_METHOD_TEMPLATE_API + loginMethods += LoginMethod.TEMPLATE_API } override fun generateUserCode() = "TEMPLATE:DO_NOT_USE" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt index 8abf079f..7b0ddfd6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/Template.kt @@ -15,10 +15,10 @@ import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.prepare -import pl.szczodrzynski.edziennik.data.api.templateLoginMethods import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -52,11 +52,11 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| __/ | |__*/ - override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) { + override fun sync(featureTypes: Set?, onlyEndpoints: Set?, arguments: JsonObject?) { data.arguments = arguments - data.prepare(templateLoginMethods, TemplateFeatures, featureIds, viewId, onlyEndpoints) - d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}") - d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + data.prepare(TemplateFeatures, featureTypes, onlyEndpoints) + d(TAG, "LoginMethod IDs: ${data.targetLoginMethods}") + d(TAG, "Endpoint IDs: ${data.targetEndpoints}") TemplateLogin(data) { TemplateData(data) { completed() @@ -68,7 +68,7 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, } - override fun sendMessage(recipients: List, subject: String, text: String) { + override fun sendMessage(recipients: Set, subject: String, text: String) { } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/TemplateFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/TemplateFeatures.kt index c12e2bcc..b389ea59 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/TemplateFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/TemplateFeatures.kt @@ -4,21 +4,23 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template -import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.Feature +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType const val ENDPOINT_TEMPLATE_WEB_SAMPLE = 9991 const val ENDPOINT_TEMPLATE_WEB_SAMPLE_2 = 9992 const val ENDPOINT_TEMPLATE_API_SAMPLE = 9993 val TemplateFeatures = listOf( - Feature(LOGIN_TYPE_TEMPLATE, FEATURE_STUDENT_INFO, listOf( - ENDPOINT_TEMPLATE_WEB_SAMPLE to LOGIN_METHOD_TEMPLATE_WEB - ), listOf(LOGIN_METHOD_TEMPLATE_WEB)), - Feature(LOGIN_TYPE_TEMPLATE, FEATURE_SCHOOL_INFO, listOf( - ENDPOINT_TEMPLATE_WEB_SAMPLE_2 to LOGIN_METHOD_TEMPLATE_WEB - ), listOf(LOGIN_METHOD_TEMPLATE_WEB)), - Feature(LOGIN_TYPE_TEMPLATE, FEATURE_GRADES, listOf( - ENDPOINT_TEMPLATE_API_SAMPLE to LOGIN_METHOD_TEMPLATE_API - ), listOf(LOGIN_METHOD_TEMPLATE_API)) + Feature(LoginType.TEMPLATE, FeatureType.STUDENT_INFO, listOf( + ENDPOINT_TEMPLATE_WEB_SAMPLE to LoginMethod.TEMPLATE_WEB + )), + Feature(LoginType.TEMPLATE, FeatureType.SCHOOL_INFO, listOf( + ENDPOINT_TEMPLATE_WEB_SAMPLE_2 to LoginMethod.TEMPLATE_WEB + )), + Feature(LoginType.TEMPLATE, FeatureType.GRADES, listOf( + ENDPOINT_TEMPLATE_API_SAMPLE to LoginMethod.TEMPLATE_API + )) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/TemplateData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/TemplateData.kt index 3489555f..4b759e34 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/TemplateData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/TemplateData.kt @@ -24,7 +24,7 @@ class TemplateData(val data: DataTemplate, val onSuccess: () -> Unit) { } private fun nextEndpoint(onSuccess: () -> Unit) { - if (data.targetEndpointIds.isEmpty()) { + if (data.targetEndpoints.isEmpty()) { onSuccess() return } @@ -32,8 +32,8 @@ class TemplateData(val data: DataTemplate, val onSuccess: () -> Unit) { onSuccess() return } - val id = data.targetEndpointIds.firstKey() - val lastSync = data.targetEndpointIds.remove(id) + val id = data.targetEndpoints.firstKey() + val lastSync = data.targetEndpoints.remove(id) useEndpoint(id, lastSync) { endpointId -> data.progress(data.progressStep) nextEndpoint(onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/api/TemplateApiSample.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/api/TemplateApiSample.kt index d61dc8f9..62df262e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/api/TemplateApiSample.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/api/TemplateApiSample.kt @@ -4,11 +4,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template.data.api -import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.data.api.edziennik.template.DataTemplate import pl.szczodrzynski.edziennik.data.api.edziennik.template.ENDPOINT_TEMPLATE_API_SAMPLE import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateApi import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.ext.DAY class TemplateApiSample(override val data: DataTemplate, @@ -29,9 +29,7 @@ class TemplateApiSample(override val data: DataTemplate, // not sooner than two days later data.setSyncNext(ENDPOINT_TEMPLATE_API_SAMPLE, 2 * DAY) // in two days OR on explicit "grades" sync - data.setSyncNext(ENDPOINT_TEMPLATE_API_SAMPLE, 2 * DAY, MainActivity.DRAWER_ITEM_GRADES) - // only if sync is executed on Home view - data.setSyncNext(ENDPOINT_TEMPLATE_API_SAMPLE, syncIn = null, viewId = MainActivity.DRAWER_ITEM_HOME) + data.setSyncNext(ENDPOINT_TEMPLATE_API_SAMPLE, 2 * DAY, FeatureType.GRADES) // always, in every sync data.setSyncNext(ENDPOINT_TEMPLATE_API_SAMPLE, SYNC_ALWAYS) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample.kt index 0732710a..5d6d457b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample.kt @@ -4,12 +4,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME import pl.szczodrzynski.edziennik.data.api.edziennik.template.DataTemplate import pl.szczodrzynski.edziennik.data.api.edziennik.template.ENDPOINT_TEMPLATE_WEB_SAMPLE import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateWeb import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.ext.DAY class TemplateWebSample(override val data: DataTemplate, @@ -30,9 +29,7 @@ class TemplateWebSample(override val data: DataTemplate, // not sooner than two days later data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE, 2 * DAY) // in two days OR on explicit "grades" sync - data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE, 2 * DAY, DRAWER_ITEM_GRADES) - // only if sync is executed on Home view - data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE, syncIn = null, viewId = DRAWER_ITEM_HOME) + data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE, 2 * DAY, FeatureType.GRADES) // always, in every sync data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE, SYNC_ALWAYS) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample2.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample2.kt index ecf41b64..0125635d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample2.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/data/web/TemplateWebSample2.kt @@ -4,11 +4,11 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web -import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.data.api.edziennik.template.DataTemplate import pl.szczodrzynski.edziennik.data.api.edziennik.template.ENDPOINT_TEMPLATE_WEB_SAMPLE_2 import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateWeb import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.ext.DAY class TemplateWebSample2(override val data: DataTemplate, @@ -29,9 +29,7 @@ class TemplateWebSample2(override val data: DataTemplate, // not sooner than two days later data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE_2, 2 * DAY) // in two days OR on explicit "grades" sync - data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE_2, 2 * DAY, MainActivity.DRAWER_ITEM_GRADES) - // only if sync is executed on Home view - data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE_2, syncIn = null, viewId = MainActivity.DRAWER_ITEM_HOME) + data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE_2, 2 * DAY, FeatureType.GRADES) // always, in every sync data.setSyncNext(ENDPOINT_TEMPLATE_WEB_SAMPLE_2, SYNC_ALWAYS) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLogin.kt index b11eef13..82ee669a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/template/login/TemplateLogin.kt @@ -5,9 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.template.login import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_TEMPLATE_API -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_TEMPLATE_WEB import pl.szczodrzynski.edziennik.data.api.edziennik.template.DataTemplate +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.utils.Utils class TemplateLogin(val data: DataTemplate, val onSuccess: () -> Unit) { @@ -22,7 +21,7 @@ class TemplateLogin(val data: DataTemplate, val onSuccess: () -> Unit) { } private fun nextLoginMethod(onSuccess: () -> Unit) { - if (data.targetLoginMethodIds.isEmpty()) { + if (data.targetLoginMethods.isEmpty()) { onSuccess() return } @@ -30,30 +29,31 @@ class TemplateLogin(val data: DataTemplate, val onSuccess: () -> Unit) { onSuccess() return } - useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + useLoginMethod(data.targetLoginMethods.removeAt(0)) { usedMethod -> data.progress(data.progressStep) - if (usedMethodId != -1) - data.loginMethods.add(usedMethodId) + if (usedMethod != null) + data.loginMethods.add(usedMethod) nextLoginMethod(onSuccess) } } - private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + private fun useLoginMethod(loginMethod: LoginMethod, onSuccess: (usedMethod: LoginMethod?) -> Unit) { // this should never be true - if (data.loginMethods.contains(loginMethodId)) { - onSuccess(-1) + if (data.loginMethods.contains(loginMethod)) { + onSuccess(null) return } - Utils.d(TAG, "Using login method $loginMethodId") - when (loginMethodId) { - LOGIN_METHOD_TEMPLATE_WEB -> { + Utils.d(TAG, "Using login method $loginMethod") + when (loginMethod) { + LoginMethod.TEMPLATE_WEB -> { data.startProgress(R.string.edziennik_progress_login_template_web) - TemplateLoginWeb(data) { onSuccess(loginMethodId) } + TemplateLoginWeb(data) { onSuccess(loginMethod) } } - LOGIN_METHOD_TEMPLATE_API -> { + LoginMethod.TEMPLATE_API -> { data.startProgress(R.string.edziennik_progress_login_template_api) - TemplateLoginApi(data) { onSuccess(loginMethodId) } + TemplateLoginApi(data) { onSuccess(loginMethod) } } + else -> {} } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt index 5cd054f8..f7149093 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/DataUsos.kt @@ -5,10 +5,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod class DataUsos( app: App, @@ -21,7 +21,7 @@ class DataUsos( override fun satisfyLoginMethods() { loginMethods.clear() if (isApiLoginValid()) { - loginMethods += LOGIN_METHOD_USOS_API + loginMethods += LoginMethod.USOS_API } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt index cbf92ca8..61cc0fda 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/Usos.kt @@ -14,10 +14,10 @@ import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.prepare -import pl.szczodrzynski.edziennik.data.api.usosLoginMethods import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -49,15 +49,14 @@ class Usos( } override fun sync( - featureIds: List, - viewId: Int?, - onlyEndpoints: List?, + featureTypes: Set?, + onlyEndpoints: Set?, arguments: JsonObject?, ) { data.arguments = arguments - data.prepare(usosLoginMethods, UsosFeatures, featureIds, viewId, onlyEndpoints) - d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}") - d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + data.prepare(UsosFeatures, featureTypes, onlyEndpoints) + d(TAG, "LoginMethod IDs: ${data.targetLoginMethods}") + d(TAG, "Endpoint IDs: ${data.targetEndpoints}") UsosLogin(data) { UsosData(data) { completed() @@ -66,7 +65,7 @@ class Usos( } override fun getMessage(message: MessageFull) {} - override fun sendMessage(recipients: List, subject: String, text: String) {} + override fun sendMessage(recipients: Set, subject: String, text: String) {} override fun markAllAnnouncementsAsRead() {} override fun getAnnouncement(announcement: AnnouncementFull) {} override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt index 50c15582..f36580fb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/UsosFeatures.kt @@ -6,6 +6,9 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.Feature +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType const val ENDPOINT_USOS_API_USER = 7000 const val ENDPOINT_USOS_API_TERMS = 7010 @@ -16,24 +19,24 @@ val UsosFeatures = listOf( /* * Student information */ - Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf( - ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API, - ), listOf(LOGIN_METHOD_USOS_API)), + Feature(LoginType.USOS, FeatureType.STUDENT_INFO, listOf( + ENDPOINT_USOS_API_USER to LoginMethod.USOS_API, + )), /* * Terms & courses */ - Feature(LOGIN_TYPE_USOS, FEATURE_SCHOOL_INFO, listOf( - ENDPOINT_USOS_API_TERMS to LOGIN_METHOD_USOS_API, - ), listOf(LOGIN_METHOD_USOS_API)), - Feature(LOGIN_TYPE_USOS, FEATURE_TEAM_INFO, listOf( - ENDPOINT_USOS_API_COURSES to LOGIN_METHOD_USOS_API, - ), listOf(LOGIN_METHOD_USOS_API)), + Feature(LoginType.USOS, FeatureType.SCHOOL_INFO, listOf( + ENDPOINT_USOS_API_TERMS to LoginMethod.USOS_API, + )), + Feature(LoginType.USOS, FeatureType.TEAM_INFO, listOf( + ENDPOINT_USOS_API_COURSES to LoginMethod.USOS_API, + )), /* * Timetable */ - Feature(LOGIN_TYPE_USOS, FEATURE_TIMETABLE, listOf( - ENDPOINT_USOS_API_TIMETABLE to LOGIN_METHOD_USOS_API, - ), listOf(LOGIN_METHOD_USOS_API)), + Feature(LoginType.USOS, FeatureType.TIMETABLE, listOf( + ENDPOINT_USOS_API_TIMETABLE to LoginMethod.USOS_API, + )), ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt index d688bebf..dbccb16b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/UsosData.kt @@ -23,7 +23,7 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { } private fun nextEndpoint(onSuccess: () -> Unit) { - if (data.targetEndpointIds.isEmpty()) { + if (data.targetEndpoints.isEmpty()) { onSuccess() return } @@ -31,8 +31,8 @@ class UsosData(val data: DataUsos, val onSuccess: () -> Unit) { onSuccess() return } - val id = data.targetEndpointIds.firstKey() - val lastSync = data.targetEndpointIds.remove(id) + val id = data.targetEndpoints.firstKey() + val lastSync = data.targetEndpoints.remove(id) useEndpoint(id, lastSync) { endpointId -> data.progress(data.progressStep) nextEndpoint(onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt index 6c1acc54..fa625d4d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiTimetable.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -122,7 +123,7 @@ class UsosApiTimetable( if (lesson.type != Lesson.TYPE_NORMAL) data.metadataList += Metadata( profileId, - Metadata.TYPE_LESSON_CHANGE, + MetadataType.LESSON_CHANGE, lesson.id, seen, seen, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt index 4cb38cc6..f839511c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/firstlogin/UsosFirstLogin.kt @@ -7,14 +7,13 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin import com.google.gson.JsonObject import org.greenrobot.eventbus.EventBus import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS -import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.* class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { @@ -25,9 +24,7 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { private val api = UsosApi(data, null) init { - val loginStoreId = data.loginStore.id - val loginStoreType = LOGIN_TYPE_USOS - var firstProfileId = loginStoreId + var firstProfileId = data.loginStore.id UsosLoginApi(data) { api.apiRequest( @@ -60,7 +57,8 @@ class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) { val profile = Profile( id = firstProfileId++, - loginStoreId = loginStoreId, loginStoreType = loginStoreType, + loginStoreId = data.loginStore.id, + loginStoreType = LoginType.USOS, name = studentName, subname = data.schoolId, studentNameLong = studentName, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt index 599b8f16..3f745b34 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/login/UsosLogin.kt @@ -5,8 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.utils.Utils.d class UsosLogin(val data: DataUsos, val onSuccess: () -> Unit) { @@ -21,7 +21,7 @@ class UsosLogin(val data: DataUsos, val onSuccess: () -> Unit) { } private fun nextLoginMethod(onSuccess: () -> Unit) { - if (data.targetLoginMethodIds.isEmpty()) { + if (data.targetLoginMethods.isEmpty()) { onSuccess() return } @@ -29,26 +29,27 @@ class UsosLogin(val data: DataUsos, val onSuccess: () -> Unit) { onSuccess() return } - useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + useLoginMethod(data.targetLoginMethods.removeAt(0)) { usedMethod -> data.progress(data.progressStep) - if (usedMethodId != -1) - data.loginMethods.add(usedMethodId) + if (usedMethod != null) + data.loginMethods.add(usedMethod) nextLoginMethod(onSuccess) } } - private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + private fun useLoginMethod(loginMethod: LoginMethod, onSuccess: (usedMethod: LoginMethod?) -> Unit) { // this should never be true - if (data.loginMethods.contains(loginMethodId)) { - onSuccess(-1) + if (data.loginMethods.contains(loginMethod)) { + onSuccess(null) return } - d(TAG, "Using login method $loginMethodId") - when (loginMethodId) { - LOGIN_METHOD_USOS_API -> { + d(TAG, "Using login method $loginMethod") + when (loginMethod) { + LoginMethod.USOS_API -> { data.startProgress(R.string.edziennik_progress_login_usos_api) - UsosLoginApi(data) { onSuccess(loginMethodId) } + UsosLoginApi(data) { onSuccess(loginMethod) } } + else -> {} } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt index 0c2bc91c..c1bf0074 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/DataVulcan.kt @@ -6,11 +6,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_HEBE -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_WEB_MAIN import pl.szczodrzynski.edziennik.data.api.models.Data import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.crc16 import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty @@ -28,10 +27,10 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app override fun satisfyLoginMethods() { loginMethods.clear() if (isWebMainLoginValid()) { - loginMethods += LOGIN_METHOD_VULCAN_WEB_MAIN + loginMethods += LoginMethod.VULCAN_WEB_MAIN } if (isHebeLoginValid()) { - loginMethods += LOGIN_METHOD_VULCAN_HEBE + loginMethods += LoginMethod.VULCAN_HEBE } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt index 37af4b69..ca7a2d21 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/Vulcan.kt @@ -7,7 +7,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan import com.google.gson.JsonObject import org.greenrobot.eventbus.EventBus import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.data.api.ERROR_ONEDRIVE_DOWNLOAD +import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED import pl.szczodrzynski.edziennik.data.api.edziennik.helper.OneDriveDownloadAttachment import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeMessagesChangeStatus @@ -21,9 +22,14 @@ import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.data.api.models.ApiError +import pl.szczodrzynski.edziennik.data.api.prepare +import pl.szczodrzynski.edziennik.data.api.prepareFor import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull @@ -60,24 +66,24 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| __/ | |__*/ - override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) { + override fun sync(featureTypes: Set?, onlyEndpoints: Set?, arguments: JsonObject?) { data.arguments = arguments - data.prepare(vulcanLoginMethods, VulcanFeatures, featureIds, viewId, onlyEndpoints) + data.prepare(VulcanFeatures, featureTypes, onlyEndpoints) login() } - private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) { - if (data.loginStore.mode == LOGIN_MODE_VULCAN_API) { + private fun login(loginMethod: LoginMethod? = null, afterLogin: (() -> Unit)? = null) { + if (data.loginStore.mode == LoginMode.VULCAN_API) { data.error(TAG, ERROR_VULCAN_API_DEPRECATED) return } - d(TAG, "Trying to login with ${data.targetLoginMethodIds}") + d(TAG, "Trying to login with ${data.targetLoginMethods}") if (internalErrorList.isNotEmpty()) { d(TAG, " - Internal errors:") internalErrorList.forEach { d(TAG, " - code $it") } } - loginMethodId?.let { data.prepareFor(vulcanLoginMethods, it) } + loginMethod?.let { data.prepareFor(it) } afterLogin?.let { this.afterLogin = it } VulcanLogin(data) { data() @@ -85,7 +91,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va } private fun data() { - d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + d(TAG, "Endpoint IDs: ${data.targetEndpoints}") if (internalErrorList.isNotEmpty()) { d(TAG, " - Internal errors:") internalErrorList.forEach { d(TAG, " - code $it") } @@ -96,7 +102,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va } override fun getMessage(message: MessageFull) { - login(LOGIN_METHOD_VULCAN_HEBE) { + login(LoginMethod.VULCAN_HEBE) { if (message.seen) { EventBus.getDefault().postSticky(MessageGetEvent(message)) completed() @@ -108,8 +114,8 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va } } - override fun sendMessage(recipients: List, subject: String, text: String) { - login(LOGIN_METHOD_VULCAN_HEBE) { + override fun sendMessage(recipients: Set, subject: String, text: String) { + login(LoginMethod.VULCAN_HEBE) { VulcanHebeSendMessage(data, recipients, subject, text) { completed() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt index 4def0214..206983a1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/VulcanFeatures.kt @@ -4,8 +4,10 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan -import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.models.Feature +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010 @@ -28,67 +30,67 @@ const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3520 val VulcanFeatures = listOf( // timetable - Feature(LOGIN_TYPE_VULCAN, FEATURE_TIMETABLE, listOf( - ENDPOINT_VULCAN_HEBE_TIMETABLE to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.TIMETABLE, listOf( + ENDPOINT_VULCAN_HEBE_TIMETABLE to LoginMethod.VULCAN_HEBE + )), // agenda - Feature(LOGIN_TYPE_VULCAN, FEATURE_AGENDA, listOf( - ENDPOINT_VULCAN_HEBE_EXAMS to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.AGENDA, listOf( + ENDPOINT_VULCAN_HEBE_EXAMS to LoginMethod.VULCAN_HEBE + )), // grades - Feature(LOGIN_TYPE_VULCAN, FEATURE_GRADES, listOf( - ENDPOINT_VULCAN_HEBE_GRADES to LOGIN_METHOD_VULCAN_HEBE, - ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.GRADES, listOf( + ENDPOINT_VULCAN_HEBE_GRADES to LoginMethod.VULCAN_HEBE, + ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY to LoginMethod.VULCAN_HEBE + )), // homework - Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf( - ENDPOINT_VULCAN_HEBE_HOMEWORK to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.HOMEWORK, listOf( + ENDPOINT_VULCAN_HEBE_HOMEWORK to LoginMethod.VULCAN_HEBE + )), // behaviour - Feature(LOGIN_TYPE_VULCAN, FEATURE_BEHAVIOUR, listOf( - ENDPOINT_VULCAN_HEBE_NOTICES to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.BEHAVIOUR, listOf( + ENDPOINT_VULCAN_HEBE_NOTICES to LoginMethod.VULCAN_HEBE + )), // attendance - Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf( - ENDPOINT_VULCAN_HEBE_ATTENDANCE to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.ATTENDANCE, listOf( + ENDPOINT_VULCAN_HEBE_ATTENDANCE to LoginMethod.VULCAN_HEBE + )), // messages - Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf( - ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), - Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf( - ENDPOINT_VULCAN_HEBE_MESSAGES_SENT to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)), + Feature(LoginType.VULCAN, FeatureType.MESSAGES_INBOX, listOf( + ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX to LoginMethod.VULCAN_HEBE + )), + Feature(LoginType.VULCAN, FeatureType.MESSAGES_SENT, listOf( + ENDPOINT_VULCAN_HEBE_MESSAGES_SENT to LoginMethod.VULCAN_HEBE + )), // push config - Feature(LOGIN_TYPE_VULCAN, FEATURE_PUSH_CONFIG, listOf( - ENDPOINT_VULCAN_HEBE_PUSH_CONFIG to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)).withShouldSync { data -> + Feature(LoginType.VULCAN, FeatureType.PUSH_CONFIG, listOf( + ENDPOINT_VULCAN_HEBE_PUSH_CONFIG to LoginMethod.VULCAN_HEBE + )).withShouldSync { data -> !data.app.config.sync.tokenVulcanList.contains(data.profileId) }, /** * Lucky number - using WEB Main. */ - Feature(LOGIN_TYPE_VULCAN, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS to LOGIN_METHOD_VULCAN_WEB_MAIN - ), listOf(LOGIN_METHOD_VULCAN_WEB_MAIN)) + Feature(LoginType.VULCAN, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS to LoginMethod.VULCAN_WEB_MAIN + )) .withShouldSync { data -> data.shouldSyncLuckyNumber() } .withPriority(2), /** * Lucky number - using Hebe API */ - Feature(LOGIN_TYPE_VULCAN, FEATURE_LUCKY_NUMBER, listOf( - ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER to LOGIN_METHOD_VULCAN_HEBE - ), listOf(LOGIN_METHOD_VULCAN_HEBE)) + Feature(LoginType.VULCAN, FeatureType.LUCKY_NUMBER, listOf( + ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER to LoginMethod.VULCAN_HEBE + )) .withShouldSync { data -> data.shouldSyncLuckyNumber() } .withPriority(1), - Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf( - ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE, - ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE, - ENDPOINT_VULCAN_HEBE_TEACHERS to LOGIN_METHOD_VULCAN_HEBE, - ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES to LOGIN_METHOD_VULCAN_HEBE, - ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2 to LOGIN_METHOD_VULCAN_HEBE, - ), listOf(LOGIN_METHOD_VULCAN_HEBE)) + Feature(LoginType.VULCAN, FeatureType.ALWAYS_NEEDED, listOf( + ENDPOINT_VULCAN_HEBE_MAIN to LoginMethod.VULCAN_HEBE, + ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LoginMethod.VULCAN_HEBE, + ENDPOINT_VULCAN_HEBE_TEACHERS to LoginMethod.VULCAN_HEBE, + ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES to LoginMethod.VULCAN_HEBE, + ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2 to LoginMethod.VULCAN_HEBE, + )) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt index 4b3f961f..41014919 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanData.kt @@ -51,7 +51,7 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { } private fun nextEndpoint(onSuccess: () -> Unit) { - if (data.targetEndpointIds.isEmpty()) { + if (data.targetEndpoints.isEmpty()) { onSuccess() return } @@ -59,8 +59,8 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { onSuccess() return } - val id = data.targetEndpointIds.firstKey() - val lastSync = data.targetEndpointIds.remove(id) + val id = data.targetEndpoints.firstKey() + val lastSync = data.targetEndpoints.remove(id) useEndpoint(id, lastSync) { if (firstSemesterSync && id !in firstSemesterSyncExclude) { // sync 2nd semester after every endpoint diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt index 9f3dcaea..d2a17039 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAttendance.kt @@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* class VulcanHebeAttendance( @@ -96,7 +97,7 @@ class VulcanHebeAttendance( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_ATTENDANCE, + MetadataType.ATTENDANCE, attendanceObject.id, profile?.empty ?: true || baseType == Attendance.TYPE_PRESENT_CUSTOM diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt index 308a3e26..70ccc1f9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeExams.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getString @@ -71,7 +72,7 @@ class VulcanHebeExams( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_EVENT, + MetadataType.EVENT, id, profile?.empty ?: true, profile?.empty ?: true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGradeSummary.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGradeSummary.kt index 390b0383..a2f561dc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGradeSummary.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGradeSummary.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.utils.Utils @@ -72,7 +73,7 @@ class VulcanHebeGradeSummary( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile?.empty ?: true, profile?.empty ?: true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt index f345b9e5..fc53d8b2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeGrades.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import java.text.DecimalFormat import kotlin.math.roundToInt @@ -111,7 +112,7 @@ class VulcanHebeGrades( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_GRADE, + MetadataType.GRADE, id, profile?.empty ?: true, profile?.empty ?: true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt index 06eea284..6b336b47 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeHomework.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.asJsonObjectList import pl.szczodrzynski.edziennik.ext.getJsonArray import pl.szczodrzynski.edziennik.ext.getLong @@ -79,7 +80,7 @@ class VulcanHebeHomework( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_HOMEWORK, + MetadataType.HOMEWORK, id, profile?.empty ?: true, profile?.empty ?: true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeLuckyNumber.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeLuckyNumber.kt index bfa07399..993c1e30 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeLuckyNumber.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeLuckyNumber.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.utils.models.Date @@ -57,7 +58,7 @@ class VulcanHebeLuckyNumber( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_LUCKY_NUMBER, + MetadataType.LUCKY_NUMBER, luckyNumberObject.date.value.toLong(), true, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt index ea093d14..b729fd9c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMain.kt @@ -5,13 +5,12 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe import com.google.gson.JsonArray -import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MAIN import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MAIN import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.models.Date @@ -125,7 +124,7 @@ class VulcanHebeMain( val newProfile = profile ?: Profile( profileId++, loginStoreId!!, - LOGIN_TYPE_VULCAN, + LoginType.VULCAN, studentNameLong, userLogin, studentNameLong, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt index affca1e1..8a48f65c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessages.kt @@ -4,7 +4,6 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGEBOX_MESSAGES import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX @@ -17,6 +16,8 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils @@ -141,7 +142,7 @@ class VulcanHebeMessages( data.setSeenMetadataList.add( Metadata( profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, id, readDate > 0 || messageType == TYPE_SENT, readDate > 0 || messageType == TYPE_SENT @@ -152,7 +153,7 @@ class VulcanHebeMessages( data.setSyncNext( endpointId, if (messageType == TYPE_RECEIVED) SYNC_ALWAYS else 1 * DAY, - if (messageType == TYPE_RECEIVED) null else DRAWER_ITEM_MESSAGES + if (messageType == TYPE_RECEIVED) null else FeatureType.MESSAGES_SENT ) onSuccess(endpointId) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt index 2144a768..bc8e9e9c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeMessagesChangeStatus.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.ext.JsonObject @@ -44,7 +45,7 @@ class VulcanHebeMessagesChangeStatus( data.setSeenMetadataList.add( Metadata( profileId, - Metadata.TYPE_MESSAGE, + MetadataType.MESSAGE, messageObject.id, true, true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeNotices.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeNotices.kt index be1e0545..6e8d9176 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeNotices.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeNotices.kt @@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Notice import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.* class VulcanHebeNotices( @@ -63,7 +64,7 @@ class VulcanHebeNotices( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_NOTICE, + MetadataType.NOTICE, id, profile?.empty ?: true, profile?.empty ?: true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeSendMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeSendMessage.kt index 5e607caa..19d8f0a2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeSendMessage.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeSendMessage.kt @@ -21,7 +21,7 @@ import java.util.UUID class VulcanHebeSendMessage( override val data: DataVulcan, - val recipients: List, + val recipients: Set, val subject: String, val text: String, val onSuccess: () -> Unit diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt index c20cf1bf..c14df9de 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeTimetable.kt @@ -20,6 +20,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_SHIFTED_S import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_SHIFTED_TARGET import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.getBoolean import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getJsonObject @@ -237,7 +238,7 @@ class VulcanHebeTimetable( data.metadataList.add( Metadata( profileId, - Metadata.TYPE_LESSON_CHANGE, + MetadataType.LESSON_CHANGE, lesson.id, seen, seen diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/web/VulcanWebLuckyNumber.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/web/VulcanWebLuckyNumber.kt index adb4363d..9dc707f5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/web/VulcanWebLuckyNumber.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/web/VulcanWebLuckyNumber.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanWebMain import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.getJsonArray import pl.szczodrzynski.edziennik.utils.models.Date @@ -56,7 +57,7 @@ class VulcanWebLuckyNumber(override val data: DataVulcan, data.metadataList.add( Metadata( profileId, - Metadata.TYPE_LUCKY_NUMBER, + MetadataType.LUCKY_NUMBER, luckyNumberObject.date.value.toLong(), true, profile?.empty ?: false diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt index 61502488..16d7a569 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/firstlogin/VulcanFirstLogin.kt @@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWeb import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode import pl.szczodrzynski.edziennik.ext.getJsonObject import pl.szczodrzynski.edziennik.ext.getString @@ -33,7 +34,7 @@ class VulcanFirstLogin(val data: DataVulcan, val onSuccess: () -> Unit) { private val tryingSymbols = mutableListOf() init { - if (data.loginStore.mode == LOGIN_MODE_VULCAN_WEB) { + if (data.loginStore.mode == LoginMode.VULCAN_WEB) { VulcanLoginWebMain(data) { val xml = web.readCertificate() ?: run { data.error(ApiError(TAG, ERROR_VULCAN_WEB_NO_CERTIFICATE)) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt index 3cbb7ea7..dc57acc9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/login/VulcanLogin.kt @@ -5,9 +5,8 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_HEBE -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_WEB_MAIN import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.utils.Utils class VulcanLogin(val data: DataVulcan, val onSuccess: () -> Unit) { @@ -22,7 +21,7 @@ class VulcanLogin(val data: DataVulcan, val onSuccess: () -> Unit) { } private fun nextLoginMethod(onSuccess: () -> Unit) { - if (data.targetLoginMethodIds.isEmpty()) { + if (data.targetLoginMethods.isEmpty()) { onSuccess() return } @@ -30,30 +29,31 @@ class VulcanLogin(val data: DataVulcan, val onSuccess: () -> Unit) { onSuccess() return } - useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + useLoginMethod(data.targetLoginMethods.removeAt(0)) { usedMethod -> data.progress(data.progressStep) - if (usedMethodId != -1) - data.loginMethods.add(usedMethodId) + if (usedMethod != null) + data.loginMethods.add(usedMethod) nextLoginMethod(onSuccess) } } - private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) { + private fun useLoginMethod(loginMethod: LoginMethod, onSuccess: (usedMethod: LoginMethod?) -> Unit) { // this should never be true - if (data.loginMethods.contains(loginMethodId)) { - onSuccess(-1) + if (data.loginMethods.contains(loginMethod)) { + onSuccess(null) return } - Utils.d(TAG, "Using login method $loginMethodId") - when (loginMethodId) { - LOGIN_METHOD_VULCAN_WEB_MAIN -> { + Utils.d(TAG, "Using login method $loginMethod") + when (loginMethod) { + LoginMethod.VULCAN_WEB_MAIN -> { data.startProgress(R.string.edziennik_progress_login_vulcan_web_main) - VulcanLoginWebMain(data) { onSuccess(loginMethodId) } + VulcanLoginWebMain(data) { onSuccess(loginMethod) } } - LOGIN_METHOD_VULCAN_HEBE -> { + LoginMethod.VULCAN_HEBE -> { data.startProgress(R.string.edziennik_progress_login_vulcan_api) - VulcanLoginHebe(data) { onSuccess(loginMethodId) } + VulcanLoginHebe(data) { onSuccess(loginMethod) } } + else -> {} } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt index 4943ff1e..47c85096 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikCallback.kt @@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.interfaces import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.Feature -import pl.szczodrzynski.edziennik.data.api.models.LoginMethod /** * A callback passed only to an e-register class. diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikInterface.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikInterface.kt index 153bbe18..617e3336 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikInterface.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EdziennikInterface.kt @@ -6,14 +6,15 @@ package pl.szczodrzynski.edziennik.data.api.interfaces import com.google.gson.JsonObject import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull interface EdziennikInterface { - fun sync(featureIds: List, viewId: Int? = null, onlyEndpoints: List? = null, arguments: JsonObject? = null) + fun sync(featureTypes: Set? = null, onlyEndpoints: Set? = null, arguments: JsonObject? = null) fun getMessage(message: MessageFull) - fun sendMessage(recipients: List, subject: String, text: String) + fun sendMessage(recipients: Set, subject: String, text: String) fun markAllAnnouncementsAsRead() fun getAnnouncement(announcement: AnnouncementFull) fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EndpointCallback.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EndpointCallback.kt index b44820c5..f8a65ac4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EndpointCallback.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/interfaces/EndpointCallback.kt @@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.data.api.interfaces import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.Feature -import pl.szczodrzynski.edziennik.data.api.models.LoginMethod /** * A callback passed to all [Feature]s and [LoginMethod]s diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt index 9b7137fc..2198c46c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt @@ -17,6 +17,8 @@ import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.* +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.models.Date @@ -47,7 +49,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt * A [LoginMethod] may add elements to this list only after a successful login * with that method. */ - val loginMethods = mutableListOf() + val loginMethods = mutableListOf() /** * A method which may be overridden in child Data* classes. @@ -61,12 +63,12 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt * A list of Login method IDs that are still pending * to run. */ - var targetLoginMethodIds = mutableListOf() + var targetLoginMethods = mutableListOf() /** * A map of endpoint ID to last sync time, that are still pending * to run. */ - var targetEndpointIds = sortedMapOf() + var targetEndpoints = sortedMapOf() /** * A count of all network requests to do. */ @@ -313,7 +315,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt d("Total save time: ${System.currentTimeMillis()-totalStart} ms") } - fun setSyncNext(endpointId: Int, syncIn: Long? = null, viewId: Int? = null, syncAt: Long? = null) { + fun setSyncNext(endpointId: Int, syncIn: Long? = null, forceFeatureType: FeatureType? = null, syncAt: Long? = null) { EndpointTimer(profile?.id ?: -1, endpointId).apply { syncedNow() @@ -327,8 +329,8 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt if (syncAt != null) { nextSync = syncAt } - if (viewId != null) - syncWhenView(viewId) + if (forceFeatureType != null) + syncWithFeature(forceFeatureType) endpointTimers.add(this) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Feature.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Feature.kt index fd7c7873..2007135b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Feature.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Feature.kt @@ -1,25 +1,27 @@ package pl.szczodrzynski.edziennik.data.api.models +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod +import pl.szczodrzynski.edziennik.data.db.enums.LoginType + /** * A Endpoint descriptor class. * * The API runs appropriate endpoints in order to fulfill its * feature list. * An endpoint may have its [LoginMethod] dependencies which will be - * satisfied by the API before the [endpointClass]'s constructor is invoked. + * satisfied by the API before the endpoint class is invoked. * * @param loginType type of the e-register this endpoint handles - * @param featureId a feature ID - * @param endpointIds a [List] of [Feature]s that satisfy this feature ID - * @param requiredLoginMethod a required login method, which will have to be executed before this endpoint. + * @param featureType type of the feature + * @param endpoints a [List] of endpoints and their required login methods that satisfy this feature type */ data class Feature( - val loginType: Int, - val featureId: Int, - val endpointIds: List>, - val requiredLoginMethods: List + val loginType: LoginType, + val featureType: FeatureType, + val endpoints: List>, ) { - var priority = endpointIds.size + var priority = endpoints.size fun withPriority(priority: Int): Feature { this.priority = priority return this @@ -30,4 +32,6 @@ data class Feature( this.shouldSync = shouldSync return this } + + val requiredLoginMethods by lazy { endpoints.map { it.second } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/LoginMethod.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/LoginMethod.kt deleted file mode 100644 index cf899cff..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/LoginMethod.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Kuba Szczodrzyński 2019-9-20. - */ - -package pl.szczodrzynski.edziennik.data.api.models - -import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_NOT_NEEDED -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore -import pl.szczodrzynski.edziennik.data.db.entity.Profile - -/** - * A Login Method descriptor class. - * - * This is used by the API to satisfy all [Feature]s' dependencies. - * A login method may have its own dependencies which need to be - * satisfied before the [loginMethodClass]'s constructor is invoked. - * - * @param loginType type of the e-register this login method handles - * @param loginMethodId a unique ID of this login method - * @param loginMethodClass a [Class] which constructor will be invoked when a log in is needed - * @param requiredLoginMethod a required login method (which will be called before this). May differ depending on the [Profile] and/or [LoginStore]. - */ -class LoginMethod( - val loginType: Int, - val loginMethodId: Int, - val loginMethodClass: Class<*>, - private var mIsPossible: ((profile: Profile?, loginStore: LoginStore) -> Boolean)? = null, - private var mRequiredLoginMethod: ((profile: Profile?, loginStore: LoginStore) -> Int)? = null -) { - - fun withIsPossible(isPossible: (profile: Profile?, loginStore: LoginStore) -> Boolean): LoginMethod { - this.mIsPossible = isPossible - return this - } - fun withRequiredLoginMethod(requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int): LoginMethod { - this.mRequiredLoginMethod = requiredLoginMethod - return this - } - - fun isPossible(profile: Profile?, loginStore: LoginStore): Boolean { - return mIsPossible?.invoke(profile, loginStore) ?: false - } - fun requiredLoginMethod(profile: Profile?, loginStore: LoginStore): Int { - return mRequiredLoginMethod?.invoke(profile, loginStore) ?: LOGIN_METHOD_NOT_NEEDED - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt index a9f6a69f..43e705dc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/SzkolnyApi.kt @@ -210,7 +210,7 @@ class SzkolnyApi(val app: App) : CoroutineScope { profile.userCode, profile.studentNameLong, profile.studentNameShort, - profile.loginStoreType, + profile.loginStoreType.id, teams.filter { it.profileId == profile.id }.map { it.code } ) val hash = user.toString().md5() @@ -225,7 +225,7 @@ class SzkolnyApi(val app: App) : CoroutineScope { userCodes = profiles.map { it.userCode }, users = users.keys(), lastSync = lastSyncTime, - notifications = notifications.map { ServerSyncRequest.Notification(it.profileName ?: "", it.type, it.text) } + notifications = notifications.map { ServerSyncRequest.Notification(it.profileName ?: "", it.type.id, it.text) } )).execute() val (events, notes, hasBrowsers) = parseResponse(response, updateDeviceHash = true) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt index 0b13c867..f076503a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/AppSync.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApiException import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Notification import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.ext.toErrorCode import pl.szczodrzynski.edziennik.utils.models.Date @@ -50,7 +51,7 @@ class AppSync(val app: App, val notifications: MutableList, val pr val isPast = event.date < today Metadata( event.profileId, - Metadata.TYPE_EVENT, + MetadataType.EVENT, event.id, isPast || markAsSeen || event.seen, isPast || markAsSeen || event.notified diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/Notifications.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/Notifications.kt index 3913709a..bb4f0cb1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/Notifications.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/Notifications.kt @@ -5,10 +5,11 @@ package pl.szczodrzynski.edziennik.data.api.task import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.* -import pl.szczodrzynski.edziennik.ext.getNotificationTitle +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType +import pl.szczodrzynski.edziennik.ext.resolveString +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Week @@ -55,14 +56,14 @@ class Notifications(val app: App, val notifications: MutableList, lesson.changeTeacherName ) notifications += Notification( - id = Notification.buildId(lesson.profileId, Notification.TYPE_TIMETABLE_LESSON_CHANGE, lesson.id), - title = app.getNotificationTitle(Notification.TYPE_TIMETABLE_LESSON_CHANGE), + id = Notification.buildId(lesson.profileId, NotificationType.TIMETABLE_LESSON_CHANGE, lesson.id), + title = NotificationType.TIMETABLE_LESSON_CHANGE.titleRes.resolveString(app), text = text, textLong = textLong, - type = Notification.TYPE_TIMETABLE_LESSON_CHANGE, + type = NotificationType.TIMETABLE_LESSON_CHANGE, profileId = lesson.profileId, profileName = profiles.singleOrNull { it.id == lesson.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_TIMETABLE, + navTarget = NavTarget.TIMETABLE, addedDate = System.currentTimeMillis() ).addExtra("timetableDate", lesson.displayDate?.stringY_m_d ?: "") } @@ -101,18 +102,18 @@ class Notifications(val app: App, val notifications: MutableList, event.topic.take(200) ) val type = if (event.isHomework) - Notification.TYPE_NEW_HOMEWORK + NotificationType.HOMEWORK else - Notification.TYPE_NEW_EVENT + NotificationType.EVENT notifications += Notification( id = Notification.buildId(event.profileId, type, event.id), - title = app.getNotificationTitle(type), + title = type.titleRes.resolveString(app), text = text, textLong = textLong, type = type, profileId = event.profileId, profileName = profiles.singleOrNull { it.id == event.profileId }?.name, - viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA, + navTarget = if (event.isHomework) NavTarget.HOMEWORK else NavTarget.AGENDA, addedDate = event.addedDate ).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong()) } @@ -140,18 +141,18 @@ class Notifications(val app: App, val notifications: MutableList, event.topicHtml.take(200) ) val type = if (event.isHomework) - Notification.TYPE_NEW_HOMEWORK + NotificationType.HOMEWORK else - Notification.TYPE_NEW_EVENT + NotificationType.EVENT notifications += Notification( id = Notification.buildId(event.profileId, type, event.id), - title = app.getNotificationTitle(type), + title = type.titleRes.resolveString(app), text = text, textLong = textLong, type = type, profileId = event.profileId, profileName = profiles.singleOrNull { it.id == event.profileId }?.name, - viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA, + navTarget = if (event.isHomework) NavTarget.HOMEWORK else NavTarget.AGENDA, addedDate = event.addedDate ).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong()) } @@ -181,14 +182,14 @@ class Notifications(val app: App, val notifications: MutableList, grade.teacherName ?: "-" ) notifications += Notification( - id = Notification.buildId(grade.profileId, Notification.TYPE_NEW_GRADE, grade.id), - title = app.getNotificationTitle(Notification.TYPE_NEW_GRADE), + id = Notification.buildId(grade.profileId, NotificationType.GRADE, grade.id), + title = NotificationType.GRADE.titleRes.resolveString(app), text = text, textLong = textLong, - type = Notification.TYPE_NEW_GRADE, + type = NotificationType.GRADE, profileId = grade.profileId, profileName = profiles.singleOrNull { it.id == grade.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_GRADES, + navTarget = NavTarget.GRADES, addedDate = grade.addedDate ).addExtra("gradeId", grade.id).addExtra("gradesSubjectId", grade.subjectId) } @@ -216,14 +217,14 @@ class Notifications(val app: App, val notifications: MutableList, notice.text.take(200) ) notifications += Notification( - id = Notification.buildId(notice.profileId, Notification.TYPE_NEW_NOTICE, notice.id), - title = app.getNotificationTitle(Notification.TYPE_NEW_NOTICE), + id = Notification.buildId(notice.profileId, NotificationType.NOTICE, notice.id), + title = NotificationType.NOTICE.titleRes.resolveString(app), text = text, textLong = textLong, - type = Notification.TYPE_NEW_NOTICE, + type = NotificationType.NOTICE, profileId = notice.profileId, profileName = profiles.singleOrNull { it.id == notice.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_BEHAVIOUR, + navTarget = NavTarget.BEHAVIOUR, addedDate = notice.addedDate ).addExtra("noticeId", notice.id) } @@ -262,14 +263,14 @@ class Notifications(val app: App, val notifications: MutableList, attendance.lessonTopic ?: "-" ) notifications += Notification( - id = Notification.buildId(attendance.profileId, Notification.TYPE_NEW_ATTENDANCE, attendance.id), - title = app.getNotificationTitle(Notification.TYPE_NEW_ATTENDANCE), + id = Notification.buildId(attendance.profileId, NotificationType.ATTENDANCE, attendance.id), + title = NotificationType.ATTENDANCE.titleRes.resolveString(app), text = text, textLong = textLong, - type = Notification.TYPE_NEW_ATTENDANCE, + type = NotificationType.ATTENDANCE, profileId = attendance.profileId, profileName = profiles.singleOrNull { it.id == attendance.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_ATTENDANCE, + navTarget = NavTarget.ATTENDANCE, addedDate = attendance.addedDate ).addExtra("attendanceId", attendance.id).addExtra("attendanceSubjectId", attendance.subjectId) } @@ -283,13 +284,13 @@ class Notifications(val app: App, val notifications: MutableList, announcement.subject ) notifications += Notification( - id = Notification.buildId(announcement.profileId, Notification.TYPE_NEW_ANNOUNCEMENT, announcement.id), - title = app.getNotificationTitle(Notification.TYPE_NEW_ANNOUNCEMENT), + id = Notification.buildId(announcement.profileId, NotificationType.ANNOUNCEMENT, announcement.id), + title = NotificationType.ANNOUNCEMENT.titleRes.resolveString(app), text = text, - type = Notification.TYPE_NEW_ANNOUNCEMENT, + type = NotificationType.ANNOUNCEMENT, profileId = announcement.profileId, profileName = profiles.singleOrNull { it.id == announcement.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_ANNOUNCEMENTS, + navTarget = NavTarget.ANNOUNCEMENTS, addedDate = announcement.addedDate ).addExtra("announcementId", announcement.id) } @@ -303,13 +304,13 @@ class Notifications(val app: App, val notifications: MutableList, message.subject ) notifications += Notification( - id = Notification.buildId(message.profileId, Notification.TYPE_NEW_MESSAGE, message.id), - title = app.getNotificationTitle(Notification.TYPE_NEW_MESSAGE), + id = Notification.buildId(message.profileId, NotificationType.MESSAGE, message.id), + title = NotificationType.MESSAGE.titleRes.resolveString(app), text = text, - type = Notification.TYPE_NEW_MESSAGE, + type = NotificationType.MESSAGE, profileId = message.profileId, profileName = profiles.singleOrNull { it.id == message.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_MESSAGES, + navTarget = NavTarget.MESSAGES, addedDate = message.addedDate ).addExtra("messageType", Message.TYPE_RECEIVED.toLong()).addExtra("messageId", message.id) } @@ -333,13 +334,13 @@ class Notifications(val app: App, val notifications: MutableList, } } notifications += Notification( - id = Notification.buildId(luckyNumber.profileId, Notification.TYPE_LUCKY_NUMBER, luckyNumber.date.value.toLong()), - title = app.getNotificationTitle(Notification.TYPE_LUCKY_NUMBER), + id = Notification.buildId(luckyNumber.profileId, NotificationType.LUCKY_NUMBER, luckyNumber.date.value.toLong()), + title = NotificationType.LUCKY_NUMBER.titleRes.resolveString(app), text = app.getString(text, luckyNumber.date.formattedString, luckyNumber.number), - type = Notification.TYPE_LUCKY_NUMBER, + type = NotificationType.LUCKY_NUMBER, profileId = luckyNumber.profileId, profileName = profile.name, - viewId = MainActivity.DRAWER_ITEM_HOME, + navTarget = NavTarget.HOME, addedDate = System.currentTimeMillis() ) } @@ -352,13 +353,13 @@ class Notifications(val app: App, val notifications: MutableList, teacherAbsence.teacherName ) notifications += Notification( - id = Notification.buildId(teacherAbsence.profileId, Notification.TYPE_TEACHER_ABSENCE, teacherAbsence.id), - title = app.getNotificationTitle(Notification.TYPE_TEACHER_ABSENCE), + id = Notification.buildId(teacherAbsence.profileId, NotificationType.TEACHER_ABSENCE, teacherAbsence.id), + title = NotificationType.TEACHER_ABSENCE.titleRes.resolveString(app), text = message, - type = Notification.TYPE_TEACHER_ABSENCE, + type = NotificationType.TEACHER_ABSENCE, profileId = teacherAbsence.profileId, profileName = profiles.singleOrNull { it.id == teacherAbsence.profileId }?.name, - viewId = MainActivity.DRAWER_ITEM_AGENDA, + navTarget = NavTarget.AGENDA, addedDate = teacherAbsence.addedDate ).addExtra("eventDate", teacherAbsence.dateFrom.value.toLong()) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/PostNotifications.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/PostNotifications.kt index 41614394..9dac8928 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/PostNotifications.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/task/PostNotifications.kt @@ -4,19 +4,19 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.os.Build -import android.util.SparseIntArray import androidx.core.app.NotificationCompat -import androidx.core.util.forEach -import androidx.core.util.set import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial -import com.mikepenz.iconics.utils.* -import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_SERVER_MESSAGE +import com.mikepenz.iconics.utils.colorRes +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType import pl.szczodrzynski.edziennik.ext.Intent import pl.szczodrzynski.edziennik.ext.asBoldSpannable import pl.szczodrzynski.edziennik.ext.concat import pl.szczodrzynski.edziennik.ext.pendingIntentFlag +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.data.db.entity.Notification as AppNotification @@ -54,26 +54,12 @@ class PostNotifications(val app: App, nList: List) { .setGroup(if (quiet) app.notificationChannelsManager.dataQuiet.key else app.notificationChannelsManager.data.key) } - private fun buildSummaryText(summaryCounts: SparseIntArray): CharSequence { + private fun buildSummaryText(summaryCounts: Map): CharSequence { val summaryTexts = mutableListOf() - summaryCounts.forEach { key, value -> + summaryCounts.forEach { (key, value) -> if (value <= 0) return@forEach - val pluralRes = when (key) { - AppNotification.TYPE_TIMETABLE_LESSON_CHANGE -> R.plurals.notification_new_timetable_change_format - AppNotification.TYPE_NEW_GRADE -> R.plurals.notification_new_grades_format - AppNotification.TYPE_NEW_EVENT -> R.plurals.notification_new_events_format - AppNotification.TYPE_NEW_HOMEWORK -> R.plurals.notification_new_homework_format - AppNotification.TYPE_NEW_SHARED_EVENT -> R.plurals.notification_new_shared_events_format - AppNotification.TYPE_NEW_SHARED_HOMEWORK -> R.plurals.notification_new_shared_homework_format - AppNotification.TYPE_NEW_MESSAGE -> R.plurals.notification_new_messages_format - AppNotification.TYPE_NEW_NOTICE -> R.plurals.notification_new_notices_format - AppNotification.TYPE_NEW_ATTENDANCE -> R.plurals.notification_new_attendance_format - AppNotification.TYPE_LUCKY_NUMBER -> R.plurals.notification_new_lucky_number_format - AppNotification.TYPE_NEW_ANNOUNCEMENT -> R.plurals.notification_new_announcements_format - else -> R.plurals.notification_other_format - } - summaryTexts += app.resources.getQuantityString(pluralRes, value, value) + summaryTexts += app.resources.getQuantityString(key.pluralRes, value, value) } return summaryTexts.concat(", ") } @@ -83,7 +69,7 @@ class PostNotifications(val app: App, nList: List) { if (count == 0) return@run val notificationManager = app.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val summaryCounts = SparseIntArray() + val summaryCounts = mutableMapOf() val newNotificationsText = app.resources.getQuantityString(R.plurals.notification_count_format, count, count) val newNotificationsShortText = app.resources.getQuantityString(R.plurals.notification_count_short_format, count, count) @@ -91,7 +77,7 @@ class PostNotifications(val app: App, nList: List) { val intent = Intent( app, MainActivity::class.java, - "fragmentId" to MainActivity.DRAWER_ITEM_NOTIFICATIONS + "fragmentId" to NavTarget.NOTIFICATIONS.id ) val summaryIntent = PendingIntent.getActivity(app, app.notificationChannelsManager.data.id, intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag()) @@ -101,7 +87,7 @@ class PostNotifications(val app: App, nList: List) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && count > 4 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && count > 8) { val summaryList = mutableListOf() nList.forEach { - summaryCounts[it.type]++ + summaryCounts[it.type] = summaryCounts.getOrDefault(it.type, 0) + 1 summaryList += listOf( it.profileName.asBoldSpannable(), it.text @@ -141,14 +127,14 @@ class PostNotifications(val app: App, nList: List) { else { // Less than 8 notifications val notifications = nList.map { - summaryCounts[it.type]++ + summaryCounts[it.type] = summaryCounts.getOrDefault(it.type, 0) + 1 NotificationCompat.Builder(app, app.notificationChannelsManager.data.key) .setContentTitle(it.profileName ?: app.getString(R.string.app_name)) .setContentText(it.text) - .setSubText(if (it.type == TYPE_SERVER_MESSAGE) null else it.title) + .setSubText(if (it.type == NotificationType.SERVER_MESSAGE) null else it.title) .setTicker("${it.profileName}: ${it.title}") .setSmallIcon(R.drawable.ic_notification) - .setLargeIcon(IconicsDrawable(app, it.getLargeIcon()).apply { + .setLargeIcon(IconicsDrawable(app, it.type.icon).apply { colorRes = R.color.colorPrimary }.toBitmap()) .setStyle(NotificationCompat.BigTextStyle() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt index b7f6ccf2..680f54e7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt @@ -44,14 +44,15 @@ import pl.szczodrzynski.edziennik.data.db.migration.* TimetableManual::class, Note::class, Metadata::class -], version = 98) +], version = 99) @TypeConverters( ConverterTime::class, ConverterDate::class, ConverterJsonObject::class, ConverterListLong::class, ConverterListString::class, - ConverterDateInt::class + ConverterDateInt::class, + ConverterEnums::class ) abstract class AppDb : RoomDatabase() { abstract fun gradeDao(): GradeDao @@ -186,6 +187,7 @@ abstract class AppDb : RoomDatabase() { Migration96(), Migration97(), Migration98(), + Migration99(), ).allowMainThreadQueries().build() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/converter/ConverterEnums.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/converter/ConverterEnums.kt new file mode 100644 index 00000000..ff3bd2b3 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/converter/ConverterEnums.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.data.db.converter + +import androidx.room.TypeConverter +import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget + +class ConverterEnums { + + @TypeConverter + fun fromEnum(value: Enum<*>?) = value?.toInt() + + @TypeConverter + fun toFeatureType(value: Int?) = value.asFeatureTypeOrNull() + + @TypeConverter + fun toLoginMethod(value: Int?) = value.asLoginMethodOrNull() + + @TypeConverter + fun toLoginMode(value: Int?) = value.asLoginModeOrNull() + + @TypeConverter + fun toLoginType(value: Int?) = value.asLoginTypeOrNull() + + @TypeConverter + fun toMetadataType(value: Int?) = value.asMetadataTypeOrNull() + + @TypeConverter + fun toNotificationType(value: Int?) = value.asNotificationTypeOrNull() + + @TypeConverter + fun toNavTarget(value: Int?) = value.asNavTargetOrNull() ?: NavTarget.HOME +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt index 88b3ccd1..aa35c810 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AnnouncementDao.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Announcement import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull @Dao @@ -26,7 +27,7 @@ abstract class AnnouncementDao : BaseDao { teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName FROM announcements LEFT JOIN teachers USING(profileId, teacherId) - LEFT JOIN metadata ON announcementId = thingId AND thingType = ${Metadata.TYPE_ANNOUNCEMENT} AND metadata.profileId = announcements.profileId + LEFT JOIN metadata ON announcementId = thingId AND thingType = 7 AND metadata.profileId = announcements.profileId """ private const val ORDER_BY = """ORDER BY addedDate DESC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt index 94be0c34..a420c5b5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/AttendanceDao.kt @@ -28,7 +28,7 @@ abstract class AttendanceDao : BaseDao { FROM attendances LEFT JOIN teachers USING(profileId, teacherId) LEFT JOIN subjects USING(profileId, subjectId) - LEFT JOIN metadata ON attendanceId = thingId AND thingType = ${Metadata.TYPE_ATTENDANCE} AND metadata.profileId = attendances.profileId + LEFT JOIN metadata ON attendanceId = thingId AND thingType = 3 AND metadata.profileId = attendances.profileId """ private const val ORDER_BY = """ORDER BY attendanceDate DESC, attendanceTime DESC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt index 24e58d02..09605429 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventDao.kt @@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.data.db.AppDb import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time @@ -35,7 +36,7 @@ abstract class EventDao : BaseDao { LEFT JOIN subjects USING(profileId, subjectId) LEFT JOIN teams USING(profileId, teamId) LEFT JOIN eventTypes USING(profileId, eventType) - LEFT JOIN metadata ON eventId = thingId AND (thingType = ${Metadata.TYPE_EVENT} OR thingType = ${Metadata.TYPE_HOMEWORK}) AND metadata.profileId = events.profileId + LEFT JOIN metadata ON eventId = thingId AND (thingType = 4 OR thingType = 5) AND metadata.profileId = events.profileId """ private const val ORDER_BY = """GROUP BY eventId ORDER BY eventDate, eventTime, addedDate ASC""" @@ -132,7 +133,7 @@ abstract class EventDao : BaseDao { dontKeepFuture(profileId, todayDate, "eventType NOT IN " + exceptTypes.toString().replace('[', '(').replace(']', ')')) } - @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = " + Metadata.TYPE_EVENT + " OR thingType = " + Metadata.TYPE_LESSON_CHANGE + " OR thingType = " + Metadata.TYPE_HOMEWORK + ") AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)") + @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND (thingType = 4 OR thingType = 6 OR thingType = 5) AND thingId IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventDate = :date)") abstract fun setSeenByDate(profileId: Int, date: Date, seen: Boolean) @Query("UPDATE events SET eventBlacklisted = :blacklisted WHERE profileId = :profileId AND eventId = :eventId") @@ -142,12 +143,12 @@ abstract class EventDao : BaseDao { abstract fun remove(profileId: Int, id: Long) @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND thingId = :thingId") - abstract fun removeMetadata(profileId: Int, thingType: Int, thingId: Long) + abstract fun removeMetadata(profileId: Int, thingType: MetadataType, thingId: Long) @Transaction open fun remove(profileId: Int, type: Long, id: Long) { remove(profileId, id) - removeMetadata(profileId, if (type == Event.TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT, id) + removeMetadata(profileId, if (type == Event.TYPE_HOMEWORK) MetadataType.HOMEWORK else MetadataType.EVENT, id) } @Transaction diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt index 6254f80b..4703eca9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/GradeDao.kt @@ -33,7 +33,7 @@ abstract class GradeDao : BaseDao { FROM grades LEFT JOIN teachers USING(profileId, teacherId) LEFT JOIN subjects USING(profileId, subjectId) - LEFT JOIN metadata ON gradeId = thingId AND thingType = ${Metadata.TYPE_GRADE} AND metadata.profileId = grades.profileId + LEFT JOIN metadata ON gradeId = thingId AND thingType = 1 AND metadata.profileId = grades.profileId """ private const val ORDER_BY = """ORDER BY addedDate DESC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt index 3c752124..b4d788c5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/LuckyNumberDao.kt @@ -25,7 +25,7 @@ abstract class LuckyNumberDao : BaseDao { SELECT * FROM luckyNumbers - LEFT JOIN metadata ON luckyNumberDate = thingId AND thingType = ${Metadata.TYPE_LUCKY_NUMBER} AND metadata.profileId = luckyNumbers.profileId + LEFT JOIN metadata ON luckyNumberDate = thingId AND thingType = 10 AND metadata.profileId = luckyNumbers.profileId """ private const val ORDER_BY = """ORDER BY luckyNumberDate DESC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt index af4e608e..59e9ca82 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MessageDao.kt @@ -26,7 +26,7 @@ abstract class MessageDao : BaseDao { teachers.teacherName ||" "|| teachers.teacherSurname AS senderName FROM messages LEFT JOIN teachers ON teachers.profileId = messages.profileId AND teacherId = senderId - LEFT JOIN metadata ON messageId = thingId AND thingType = ${Metadata.TYPE_MESSAGE} AND metadata.profileId = messages.profileId + LEFT JOIN metadata ON messageId = thingId AND thingType = 8 AND metadata.profileId = messages.profileId """ private const val ORDER_BY = """ORDER BY messageIsPinned DESC, addedDate DESC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java index ab694702..c8cb295b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java @@ -4,15 +4,6 @@ package pl.szczodrzynski.edziennik.data.db.dao; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ANNOUNCEMENT; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ATTENDANCE; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_EVENT; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_HOMEWORK; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_LESSON_CHANGE; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_MESSAGE; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_NOTICE; - import androidx.lifecycle.LiveData; import androidx.room.Dao; import androidx.room.Insert; @@ -29,6 +20,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade; import pl.szczodrzynski.edziennik.data.db.entity.Message; import pl.szczodrzynski.edziennik.data.db.entity.Metadata; import pl.szczodrzynski.edziennik.data.db.entity.Notice; +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType; import pl.szczodrzynski.edziennik.data.db.full.LessonFull; import pl.szczodrzynski.edziennik.utils.models.UnreadCounter; @@ -44,10 +36,10 @@ public abstract class MetadataDao { public abstract void addAllReplace(List metadataList); @Query("UPDATE metadata SET seen = :seen WHERE thingId = :thingId AND thingType = :thingType AND profileId = :profileId") - abstract void updateSeen(int profileId, int thingType, long thingId, boolean seen); + abstract void updateSeen(int profileId, MetadataType thingType, long thingId, boolean seen); @Query("UPDATE metadata SET notified = :notified WHERE thingId = :thingId AND thingType = :thingType AND profileId = :profileId") - abstract void updateNotified(int profileId, int thingType, long thingId, boolean notified); + abstract void updateNotified(int profileId, MetadataType thingType, long thingId, boolean notified); @@ -63,38 +55,38 @@ public abstract class MetadataDao { @Transaction public void setSeen(int profileId, Object o, boolean seen) { if (o instanceof Grade) { - if (add(new Metadata(profileId, TYPE_GRADE, ((Grade) o).getId(), seen, false)) == -1) { - updateSeen(profileId, TYPE_GRADE, ((Grade) o).getId(), seen); + if (add(new Metadata(profileId, MetadataType.GRADE, ((Grade) o).getId(), seen, false)) == -1) { + updateSeen(profileId, MetadataType.GRADE, ((Grade) o).getId(), seen); } } if (o instanceof Attendance) { - if (add(new Metadata(profileId, TYPE_ATTENDANCE, ((Attendance) o).getId(), seen, false)) == -1) { - updateSeen(profileId, TYPE_ATTENDANCE, ((Attendance) o).getId(), seen); + if (add(new Metadata(profileId, MetadataType.ATTENDANCE, ((Attendance) o).getId(), seen, false)) == -1) { + updateSeen(profileId, MetadataType.ATTENDANCE, ((Attendance) o).getId(), seen); } } if (o instanceof Notice) { - if (add(new Metadata(profileId, TYPE_NOTICE, ((Notice) o).getId(), seen, false)) == -1) { - updateSeen(profileId, TYPE_NOTICE, ((Notice) o).getId(), seen); + if (add(new Metadata(profileId, MetadataType.NOTICE, ((Notice) o).getId(), seen, false)) == -1) { + updateSeen(profileId, MetadataType.NOTICE, ((Notice) o).getId(), seen); } } if (o instanceof Event) { - if (add(new Metadata(profileId, ((Event) o).isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), seen, false)) == -1) { - updateSeen(profileId, ((Event) o).isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), seen); + if (add(new Metadata(profileId, ((Event) o).isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, ((Event) o).getId(), seen, false)) == -1) { + updateSeen(profileId, ((Event) o).isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, ((Event) o).getId(), seen); } } if (o instanceof LessonFull) { - if (add(new Metadata(profileId, TYPE_LESSON_CHANGE, ((LessonFull) o).getId(), seen, false)) == -1) { - updateSeen(profileId, TYPE_LESSON_CHANGE, ((LessonFull) o).getId(), seen); + if (add(new Metadata(profileId, MetadataType.LESSON_CHANGE, ((LessonFull) o).getId(), seen, false)) == -1) { + updateSeen(profileId, MetadataType.LESSON_CHANGE, ((LessonFull) o).getId(), seen); } } if (o instanceof Announcement) { - if (add(new Metadata(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).getId(), seen, false)) == -1) { - updateSeen(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).getId(), seen); + if (add(new Metadata(profileId, MetadataType.ANNOUNCEMENT, ((Announcement) o).getId(), seen, false)) == -1) { + updateSeen(profileId, MetadataType.ANNOUNCEMENT, ((Announcement) o).getId(), seen); } } if (o instanceof Message) { - if (add(new Metadata(profileId, TYPE_MESSAGE, ((Message) o).getId(), seen, false)) == -1) { - updateSeen(profileId, TYPE_MESSAGE, ((Message) o).getId(), seen); + if (add(new Metadata(profileId, MetadataType.MESSAGE, ((Message) o).getId(), seen, false)) == -1) { + updateSeen(profileId, MetadataType.MESSAGE, ((Message) o).getId(), seen); } } } @@ -102,38 +94,38 @@ public abstract class MetadataDao { @Transaction public void setNotified(int profileId, Object o, boolean notified) { if (o instanceof Grade) { - if (add(new Metadata(profileId, TYPE_GRADE, ((Grade) o).getId(), false, notified)) == -1) { - updateNotified(profileId, TYPE_GRADE, ((Grade) o).getId(), notified); + if (add(new Metadata(profileId, MetadataType.GRADE, ((Grade) o).getId(), false, notified)) == -1) { + updateNotified(profileId, MetadataType.GRADE, ((Grade) o).getId(), notified); } } if (o instanceof Attendance) { - if (add(new Metadata(profileId, TYPE_ATTENDANCE, ((Attendance) o).getId(), false, notified)) == -1) { - updateNotified(profileId, TYPE_ATTENDANCE, ((Attendance) o).getId(), notified); + if (add(new Metadata(profileId, MetadataType.ATTENDANCE, ((Attendance) o).getId(), false, notified)) == -1) { + updateNotified(profileId, MetadataType.ATTENDANCE, ((Attendance) o).getId(), notified); } } if (o instanceof Notice) { - if (add(new Metadata(profileId, TYPE_NOTICE, ((Notice) o).getId(), false, notified)) == -1) { - updateNotified(profileId, TYPE_NOTICE, ((Notice) o).getId(), notified); + if (add(new Metadata(profileId, MetadataType.NOTICE, ((Notice) o).getId(), false, notified)) == -1) { + updateNotified(profileId, MetadataType.NOTICE, ((Notice) o).getId(), notified); } } if (o instanceof Event) { - if (add(new Metadata(profileId, ((Event) o).isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), false, notified)) == -1) { - updateNotified(profileId, ((Event) o).isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, ((Event) o).getId(), notified); + if (add(new Metadata(profileId, ((Event) o).isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, ((Event) o).getId(), false, notified)) == -1) { + updateNotified(profileId, ((Event) o).isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, ((Event) o).getId(), notified); } } if (o instanceof LessonFull) { - if (add(new Metadata(profileId, TYPE_LESSON_CHANGE, ((LessonFull) o).getId(), false, notified)) == -1) { - updateNotified(profileId, TYPE_LESSON_CHANGE, ((LessonFull) o).getId(), notified); + if (add(new Metadata(profileId, MetadataType.LESSON_CHANGE, ((LessonFull) o).getId(), false, notified)) == -1) { + updateNotified(profileId, MetadataType.LESSON_CHANGE, ((LessonFull) o).getId(), notified); } } if (o instanceof Announcement) { - if (add(new Metadata(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).getId(), false, notified)) == -1) { - updateNotified(profileId, TYPE_ANNOUNCEMENT, ((Announcement) o).getId(), notified); + if (add(new Metadata(profileId, MetadataType.ANNOUNCEMENT, ((Announcement) o).getId(), false, notified)) == -1) { + updateNotified(profileId, MetadataType.ANNOUNCEMENT, ((Announcement) o).getId(), notified); } } if (o instanceof Message) { - if (add(new Metadata(profileId, TYPE_MESSAGE, ((Message) o).getId(), false, notified)) == -1) { - updateNotified(profileId, TYPE_MESSAGE, ((Message) o).getId(), notified); + if (add(new Metadata(profileId, MetadataType.MESSAGE, ((Message) o).getId(), false, notified)) == -1) { + updateNotified(profileId, MetadataType.MESSAGE, ((Message) o).getId(), notified); } } } @@ -141,9 +133,9 @@ public abstract class MetadataDao { @Transaction public void setBoth(int profileId, Event o, boolean seen, boolean notified, long addedDate) { if (o != null) { - if (add(new Metadata(profileId, o.isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, o.getId(), seen, notified)) == -1) { - updateSeen(profileId, o.isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, o.getId(), seen); - updateNotified(profileId, o.isHomework() ? TYPE_HOMEWORK : TYPE_EVENT, o.getId(), notified); + if (add(new Metadata(profileId, o.isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, o.getId(), seen, notified)) == -1) { + updateSeen(profileId, o.isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, o.getId(), seen); + updateNotified(profileId, o.isHomework() ? MetadataType.HOMEWORK : MetadataType.EVENT, o.getId(), notified); } } } @@ -151,18 +143,18 @@ public abstract class MetadataDao { @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND thingType = :thingType") - public abstract void setAllSeen(int profileId, int thingType, boolean seen); + public abstract void setAllSeen(int profileId, MetadataType thingType, boolean seen); @Query("UPDATE metadata SET notified = :notified WHERE profileId = :profileId AND thingType = :thingType") - public abstract void setAllNotified(int profileId, int thingType, boolean notified); + public abstract void setAllNotified(int profileId, MetadataType thingType, boolean notified); @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId") public abstract void setAllSeen(int profileId, boolean seen); - @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND thingType != " + TYPE_MESSAGE) + @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND thingType != 8") public abstract void setAllSeenExceptMessages(int profileId, boolean seen); - @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND thingType != " + TYPE_MESSAGE + " AND thingType != " + TYPE_ANNOUNCEMENT) + @Query("UPDATE metadata SET seen = :seen WHERE profileId = :profileId AND thingType != 8 AND thingType != 7") public abstract void setAllSeenExceptMessagesAndAnnouncements(int profileId, boolean seen); @Query("UPDATE metadata SET notified = :notified WHERE profileId = :profileId") @@ -174,10 +166,10 @@ public abstract class MetadataDao { @Query("SELECT count() FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND seen = 0") - public abstract LiveData countUnseen(int profileId, int thingType); + public abstract LiveData countUnseen(int profileId, MetadataType thingType); @Query("SELECT count() FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND seen = 0") - public abstract Integer countUnseenNow(int profileId, int thingType); + public abstract Integer countUnseenNow(int profileId, MetadataType thingType); @Query("SELECT count() FROM metadata WHERE profileId = :profileId AND seen = 0") public abstract LiveData countUnseen(int profileId); @@ -191,7 +183,7 @@ public abstract class MetadataDao { @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = :thingType AND thingId = :thingId") - public abstract void delete(int profileId, int thingType, long thingId); + public abstract void delete(int profileId, MetadataType thingType, long thingId); @Query("DELETE FROM metadata WHERE profileId = :profileId") public abstract void deleteAll(int profileId); @@ -203,25 +195,25 @@ public abstract class MetadataDao { - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_GRADE+" AND thingId NOT IN (SELECT gradeId FROM grades WHERE profileId = :profileId);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 1 AND thingId NOT IN (SELECT gradeId FROM grades WHERE profileId = :profileId);") public abstract void deleteUnusedGrades(int profileId); - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_NOTICE+" AND thingId NOT IN (SELECT noticeId FROM notices WHERE profileId = :profileId);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 2 AND thingId NOT IN (SELECT noticeId FROM notices WHERE profileId = :profileId);") public abstract void deleteUnusedNotices(int profileId); - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_ATTENDANCE+" AND thingId NOT IN (SELECT attendanceId FROM attendances WHERE profileId = :profileId);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 3 AND thingId NOT IN (SELECT attendanceId FROM attendances WHERE profileId = :profileId);") public abstract void deleteUnusedAttendance(int profileId); - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_EVENT+" AND thingId NOT IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventType != -1);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 4 AND thingId NOT IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventType != -1);") public abstract void deleteUnusedEvents(int profileId); - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_HOMEWORK+" AND thingId NOT IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventType = -1);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 5 AND thingId NOT IN (SELECT eventId FROM events WHERE profileId = :profileId AND eventType = -1);") public abstract void deleteUnusedHomework(int profileId); - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_ANNOUNCEMENT+" AND thingId NOT IN (SELECT announcementId FROM announcements WHERE profileId = :profileId);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 7 AND thingId NOT IN (SELECT announcementId FROM announcements WHERE profileId = :profileId);") public abstract void deleteUnusedAnnouncements(int profileId); - @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = "+TYPE_MESSAGE+" AND thingId NOT IN (SELECT messageId FROM messages WHERE profileId = :profileId);") + @Query("DELETE FROM metadata WHERE profileId = :profileId AND thingType = 8 AND thingId NOT IN (SELECT messageId FROM messages WHERE profileId = :profileId);") public abstract void deleteUnusedMessages(int profileId); @Transaction diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt index 51f3e839..20443c22 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/NoticeDao.kt @@ -26,7 +26,7 @@ abstract class NoticeDao : BaseDao { teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName FROM notices LEFT JOIN teachers USING(profileId, teacherId) - LEFT JOIN metadata ON noticeId = thingId AND thingType = ${Metadata.TYPE_NOTICE} AND metadata.profileId = notices.profileId + LEFT JOIN metadata ON noticeId = thingId AND thingType = 2 AND metadata.profileId = notices.profileId """ private const val ORDER_BY = """ORDER BY addedDate DESC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt index f12248b8..de65f730 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TeacherAbsenceDao.kt @@ -27,7 +27,7 @@ abstract class TeacherAbsenceDao : BaseDao { teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName FROM teacherAbsence LEFT JOIN teachers USING(profileId, teacherId) - LEFT JOIN metadata ON teacherAbsenceId = thingId AND thingType = ${Metadata.TYPE_TEACHER_ABSENCE} AND metadata.profileId = teacherAbsence.profileId + LEFT JOIN metadata ON teacherAbsenceId = thingId AND thingType = 9 AND metadata.profileId = teacherAbsence.profileId """ private const val ORDER_BY = """ORDER BY teacherAbsenceDateFrom ASC""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt index 4201a51d..0c3d6c2b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/TimetableDao.kt @@ -38,7 +38,7 @@ abstract class TimetableDao : BaseDao { LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId - LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId + LEFT JOIN metadata ON id = thingId AND thingType = 6 AND metadata.profileId = timetable.profileId """ private const val ORDER_BY = """ORDER BY profileId, id, type""" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EndpointTimer.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EndpointTimer.kt index 05676131..a40df7da 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EndpointTimer.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EndpointTimer.kt @@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.data.db.entity import androidx.room.ColumnInfo import androidx.room.Entity +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType const val SYNC_NEVER = 0L const val SYNC_ALWAYS = 1L @@ -26,7 +27,7 @@ data class EndpointTimer ( var nextSync: Long = SYNC_ALWAYS, @ColumnInfo(name = "endpointViewId") - var viewId: Int? = null + var featureType: FeatureType? = null ) { @@ -49,17 +50,15 @@ data class EndpointTimer ( } /** - * Set this timer to sync only if [viewId] is the only + * Set this timer to sync only if [featureType] is the only * selected feature during the current process. - * - * [viewId] may be [DRAWER_ITEM_HOME] to sync only if all features are selected. */ - fun syncWhenView(viewId: Int): EndpointTimer { + fun syncWithFeature(featureType: FeatureType): EndpointTimer { // set to never sync if nextSync is not already a timestamp if (nextSync < 10) { this.nextSync = SYNC_NEVER } - this.viewId = viewId + this.featureType = featureType return this } @@ -68,7 +67,7 @@ data class EndpointTimer ( */ fun syncAlways(): EndpointTimer { nextSync = SYNC_ALWAYS - viewId = null + featureType = null return this } @@ -77,7 +76,7 @@ data class EndpointTimer ( */ fun syncNever(): EndpointTimer { nextSync = SYNC_NEVER - viewId = null + featureType = null return this } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt index 32c0d7e7..f9ba31da 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/LoginStore.kt @@ -8,6 +8,8 @@ import android.os.Bundle import androidx.room.ColumnInfo import androidx.room.Entity import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.* @Entity(tableName = "loginStores", primaryKeys = ["loginStoreId"]) @@ -16,25 +18,14 @@ class LoginStore( val id: Int, @ColumnInfo(name = "loginStoreType") - val type: Int, + val type: LoginType, @ColumnInfo(name = "loginStoreMode") - val mode: Int, + val mode: LoginMode, @ColumnInfo(name = "loginStoreData") val data: JsonObject = JsonObject() ) { - companion object { - const val LOGIN_TYPE_MOBIDZIENNIK = 1 - const val LOGIN_TYPE_LIBRUS = 2 - const val LOGIN_TYPE_VULCAN = 4 - const val LOGIN_TYPE_IDZIENNIK = 3 - const val LOGIN_TYPE_EDUDZIENNIK = 5 - const val LOGIN_TYPE_DEMO = 20 - const val LOGIN_MODE_LIBRUS_EMAIL = 0 - const val LOGIN_MODE_LIBRUS_SYNERGIA = 1 - const val LOGIN_MODE_LIBRUS_JST = 2 - } fun hasLoginData(key: String) = data.has(key) fun getLoginData(key: String, defaultValue: Boolean) = data.getBoolean(key) ?: defaultValue @@ -64,31 +55,11 @@ class LoginStore( } } - fun type(): String { - return when (type) { - LOGIN_TYPE_MOBIDZIENNIK -> "LOGIN_TYPE_MOBIDZIENNIK" - LOGIN_TYPE_LIBRUS -> "LOGIN_TYPE_LIBRUS" - LOGIN_TYPE_IDZIENNIK -> "LOGIN_TYPE_IDZIENNIK" - LOGIN_TYPE_VULCAN -> "LOGIN_TYPE_VULCAN" - LOGIN_TYPE_DEMO -> "LOGIN_TYPE_DEMO" - else -> "unknown" - } - } - - fun mode(): String { - return when (mode) { - LOGIN_MODE_LIBRUS_EMAIL -> "LOGIN_MODE_LIBRUS_EMAIL" - LOGIN_MODE_LIBRUS_SYNERGIA -> "LOGIN_MODE_LIBRUS_SYNERGIA" - LOGIN_MODE_LIBRUS_JST -> "LOGIN_MODE_LIBRUS_JST" - else -> "unknown" - } - } - override fun toString(): String { return "LoginStore{" + "id=" + id + - ", type=" + type() + - ", mode=" + mode() + + ", type=" + type + + ", mode=" + mode + ", data=" + data + '}' } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Metadata.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Metadata.java index 7374d915..7b3544df 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Metadata.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Metadata.java @@ -4,47 +4,32 @@ package pl.szczodrzynski.edziennik.data.db.entity; +import androidx.annotation.NonNull; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.Ignore; import androidx.room.Index; import androidx.room.PrimaryKey; +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType; @Entity(tableName = "metadata", indices = {@Index(value = {"profileId", "thingType", "thingId"}, unique = true)} ) public class Metadata { - public static final int TYPE_GRADE = 1; - public static final int TYPE_NOTICE = 2; - public static final int TYPE_ATTENDANCE = 3; - public static final int TYPE_EVENT = 4; - public static final int TYPE_HOMEWORK = 5; - public static final int TYPE_LESSON_CHANGE = 6; - public static final int TYPE_ANNOUNCEMENT = 7; - public static final int TYPE_MESSAGE = 8; - public static final int TYPE_TEACHER_ABSENCE = 9; - public static final int TYPE_LUCKY_NUMBER = 10; - public int profileId; @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "metadataId") public int id; - public int thingType; + @NonNull + public MetadataType thingType; public long thingId; public boolean seen; public boolean notified; - @Ignore - public Metadata() { - this.profileId = -1; - this.seen = false; - this.notified = false; - } - - public Metadata(int profileId, int thingType, long thingId, boolean seen, boolean notified) { + public Metadata(int profileId, @NonNull MetadataType thingType, long thingId, boolean seen, boolean notified) { this.profileId = profileId; this.thingType = thingType; this.thingId = thingId; @@ -52,35 +37,12 @@ public class Metadata { this.notified = notified; } - public String thingType() { - switch (thingType) { - case TYPE_GRADE: - return "TYPE_GRADE"; - case TYPE_NOTICE: - return "TYPE_NOTICE"; - case TYPE_ATTENDANCE: - return "TYPE_ATTENDANCE"; - case TYPE_EVENT: - return "TYPE_EVENT"; - case TYPE_HOMEWORK: - return "TYPE_HOMEWORK"; - case TYPE_LESSON_CHANGE: - return "TYPE_LESSON_CHANGE"; - case TYPE_ANNOUNCEMENT: - return "TYPE_ANNOUNCEMENT"; - case TYPE_MESSAGE: - return "TYPE_MESSAGE"; - default: - return "TYPE_UNKNOWN"; - } - } - @Override public String toString() { return "Metadata{" + "profileId=" + profileId + ", id=" + id + - ", thingType=" + thingType() + + ", thingType=" + thingType + ", thingId=" + thingId + ", seen=" + seen + ", notified=" + notified + diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Notification.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Notification.kt index 35208927..6c3097a4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Notification.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Notification.kt @@ -7,13 +7,17 @@ package pl.szczodrzynski.edziennik.data.db.entity import android.app.PendingIntent import android.content.Context import android.content.Intent +import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import com.google.gson.JsonObject import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType import pl.szczodrzynski.edziennik.ext.pendingIntentFlag +import pl.szczodrzynski.edziennik.ext.putExtras +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget @Entity(tableName = "notifications") data class Notification( @@ -24,43 +28,22 @@ data class Notification( val text: String, val textLong: String? = null, - val type: Int, + val type: NotificationType, val profileId: Int?, val profileName: String?, var posted: Boolean = true, - var viewId: Int? = null, + @ColumnInfo(name = "viewId") + var navTarget: NavTarget? = null, var extras: JsonObject? = null, val addedDate: Long = System.currentTimeMillis() ) { companion object { - const val TYPE_GENERAL = 0 - const val TYPE_UPDATE = 1 - const val TYPE_ERROR = 2 - const val TYPE_TIMETABLE_CHANGED = 3 - const val TYPE_TIMETABLE_LESSON_CHANGE = 4 - const val TYPE_NEW_GRADE = 5 - const val TYPE_NEW_EVENT = 6 - const val TYPE_NEW_HOMEWORK = 10 - const val TYPE_NEW_SHARED_EVENT = 7 - const val TYPE_NEW_SHARED_HOMEWORK = 12 - const val TYPE_REMOVED_SHARED_EVENT = 18 - const val TYPE_NEW_MESSAGE = 8 - const val TYPE_NEW_NOTICE = 9 - const val TYPE_NEW_ATTENDANCE = 13 - const val TYPE_SERVER_MESSAGE = 11 - const val TYPE_LUCKY_NUMBER = 14 - const val TYPE_NEW_ANNOUNCEMENT = 15 - const val TYPE_FEEDBACK_MESSAGE = 16 - const val TYPE_AUTO_ARCHIVING = 17 - const val TYPE_TEACHER_ABSENCE = 19 - const val TYPE_NEW_SHARED_NOTE = 20 - - fun buildId(profileId: Int, type: Int, itemId: Long): Long { - return 1000000000000 + profileId*10000000000 + type*100000000 + itemId; + fun buildId(profileId: Int, type: NotificationType, itemId: Long): Long { + return 1000000000000 + profileId*10000000000 + type.id*100000000 + itemId; } } @@ -78,8 +61,8 @@ data class Notification( fun fillIntent(intent: Intent) { if (profileId != -1) intent.putExtra("profileId", profileId) - if (viewId != -1) - intent.putExtra("fragmentId", viewId) + if (navTarget != null) + intent.putExtras("fragmentId" to navTarget) try { extras?.entrySet()?.forEach { (key, value) -> if (!value.isJsonPrimitive) @@ -101,20 +84,4 @@ data class Notification( fillIntent(intent) return PendingIntent.getActivity(context, id.toInt(), intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag()) } - - fun getLargeIcon(): IIcon = when (type) { - TYPE_TIMETABLE_LESSON_CHANGE -> CommunityMaterial.Icon3.cmd_timetable - TYPE_NEW_GRADE -> CommunityMaterial.Icon3.cmd_numeric_5_box_outline - TYPE_NEW_EVENT -> CommunityMaterial.Icon.cmd_calendar_outline - TYPE_NEW_HOMEWORK -> CommunityMaterial.Icon3.cmd_notebook_outline - TYPE_NEW_SHARED_EVENT -> CommunityMaterial.Icon.cmd_calendar_outline - TYPE_NEW_SHARED_HOMEWORK -> CommunityMaterial.Icon3.cmd_notebook_outline - TYPE_NEW_MESSAGE -> CommunityMaterial.Icon.cmd_email_outline - TYPE_NEW_NOTICE -> CommunityMaterial.Icon.cmd_emoticon_outline - TYPE_NEW_ATTENDANCE -> CommunityMaterial.Icon.cmd_calendar_remove_outline - TYPE_LUCKY_NUMBER -> CommunityMaterial.Icon.cmd_emoticon_excited_outline - TYPE_NEW_ANNOUNCEMENT -> CommunityMaterial.Icon.cmd_bullhorn_outline - TYPE_NEW_SHARED_NOTE -> CommunityMaterial.Icon3.cmd_playlist_edit - else -> CommunityMaterial.Icon.cmd_bell_ring_outline - } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt index b1615fbc..012948c0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt @@ -16,8 +16,7 @@ import androidx.room.Ignore import com.google.gson.JsonObject import pl.droidsonroids.gif.GifDrawable import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.MainActivity -import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.utils.ProfileImageHolder import pl.szczodrzynski.edziennik.utils.models.Date @@ -31,7 +30,7 @@ open class Profile( @ColumnInfo(name = "profileId") override var id: Int, /* needs to be var for ProfileArchiver */ val loginStoreId: Int, - val loginStoreType: Int, + val loginStoreType: LoginType, override var name: String = "", override var subname: String? = null, @@ -134,16 +133,8 @@ open class Profile( val accountOwnerName get() = accountName ?: studentNameLong - val registerName - get() = when (loginStoreType) { - LOGIN_TYPE_LIBRUS -> "librus" - LOGIN_TYPE_VULCAN -> "vulcan" - LOGIN_TYPE_IDZIENNIK -> "idziennik" - LOGIN_TYPE_MOBIDZIENNIK -> "mobidziennik" - LOGIN_TYPE_PODLASIE -> "podlasie" - LOGIN_TYPE_EDUDZIENNIK -> "edudziennik" - else -> "unknown" - } + @Ignore + val registerName = loginStoreType.name.lowercase() val canShare get() = registration == REGISTRATION_ENABLED && !archived @@ -193,54 +184,4 @@ open class Profile( override fun applyImageTo(imageView: ImageView) { getImageHolder(imageView.context).applyTo(imageView) } - - val supportedFragments: List - get() = when (loginStoreType) { - LoginStore.LOGIN_TYPE_MOBIDZIENNIK, - LoginStore.LOGIN_TYPE_DEMO, - LoginStore.LOGIN_TYPE_VULCAN -> listOf( - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES, - MainActivity.DRAWER_ITEM_MESSAGES, - MainActivity.DRAWER_ITEM_HOMEWORK, - MainActivity.DRAWER_ITEM_BEHAVIOUR, - MainActivity.DRAWER_ITEM_ATTENDANCE - ) - LoginStore.LOGIN_TYPE_LIBRUS, - LoginStore.LOGIN_TYPE_IDZIENNIK -> listOf( - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES, - MainActivity.DRAWER_ITEM_MESSAGES, - MainActivity.DRAWER_ITEM_HOMEWORK, - MainActivity.DRAWER_ITEM_BEHAVIOUR, - MainActivity.DRAWER_ITEM_ATTENDANCE, - MainActivity.DRAWER_ITEM_ANNOUNCEMENTS - ) - LOGIN_TYPE_EDUDZIENNIK -> listOf( - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES, - MainActivity.DRAWER_ITEM_HOMEWORK, - MainActivity.DRAWER_ITEM_BEHAVIOUR, - MainActivity.DRAWER_ITEM_ATTENDANCE, - MainActivity.DRAWER_ITEM_ANNOUNCEMENTS - ) - LOGIN_TYPE_PODLASIE -> listOf( - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES, - MainActivity.DRAWER_ITEM_HOMEWORK - ) - LOGIN_TYPE_USOS -> listOf( - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA - ) - else -> listOf( - MainActivity.DRAWER_ITEM_TIMETABLE, - MainActivity.DRAWER_ITEM_AGENDA, - MainActivity.DRAWER_ITEM_GRADES - ) - } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt new file mode 100644 index 00000000..98837920 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +import pl.szczodrzynski.edziennik.R + +enum class FeatureType( + val id: Int, + val isAlwaysNeeded: Boolean, + val nameRes: Int? = null, +) { + TIMETABLE(id = 1, isAlwaysNeeded = false, nameRes = R.string.menu_timetable), + AGENDA(id = 2, isAlwaysNeeded = false, nameRes = R.string.menu_agenda), + GRADES(id = 3, isAlwaysNeeded = false, nameRes = R.string.menu_grades), + HOMEWORK(id = 4, isAlwaysNeeded = false, nameRes = R.string.menu_homework), + BEHAVIOUR(id = 5, isAlwaysNeeded = false, nameRes = R.string.menu_notices), + ATTENDANCE(id = 6, isAlwaysNeeded = false, nameRes = R.string.menu_attendance), + MESSAGES_INBOX(id = 7, isAlwaysNeeded = false, nameRes = R.string.title_messages_inbox_single), + MESSAGES_SENT(id = 8, isAlwaysNeeded = false, nameRes = R.string.title_messages_sent_single), + ANNOUNCEMENTS(id = 9, isAlwaysNeeded = false, nameRes = R.string.menu_announcements), + + ALWAYS_NEEDED(id = 100, isAlwaysNeeded = true), + STUDENT_INFO(id = 101, isAlwaysNeeded = true), + STUDENT_NUMBER(id = 109, isAlwaysNeeded = true), + SCHOOL_INFO(id = 102, isAlwaysNeeded = true), + CLASS_INFO(id = 103, isAlwaysNeeded = true), + TEAM_INFO(id = 104, isAlwaysNeeded = true), + LUCKY_NUMBER(id = 105, isAlwaysNeeded = true), + TEACHERS(id = 106, isAlwaysNeeded = true), + SUBJECTS(id = 107, isAlwaysNeeded = true), + CLASSROOMS(id = 108, isAlwaysNeeded = true), + PUSH_CONFIG(id = 120, isAlwaysNeeded = true), +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMethod.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMethod.kt new file mode 100644 index 00000000..be298b9a --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMethod.kt @@ -0,0 +1,84 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.entity.Profile + +enum class LoginMethod( + val loginType: LoginType, + val id: Int, + val isPossible: (( + profile: Profile?, + loginStore: LoginStore, + ) -> Boolean)? = null, + val requiredLoginMethod: (( + profile: Profile?, + loginStore: LoginStore, + ) -> LoginMethod?)? = null, +) { + MOBIDZIENNIK_WEB( + loginType = LoginType.MOBIDZIENNIK, + id = 1100, + ), + MOBIDZIENNIK_API2( + loginType = LoginType.MOBIDZIENNIK, + id = 1300, + isPossible = { profile, _ -> profile?.studentData?.has("email") ?: false }, + ), + LIBRUS_PORTAL( + loginType = LoginType.LIBRUS, + id = 2100, + isPossible = { _, loginStore -> loginStore.mode == LoginMode.LIBRUS_EMAIL }, + ), + LIBRUS_API( + loginType = LoginType.LIBRUS, + id = 2200, + isPossible = { _, loginStore -> loginStore.mode != LoginMode.LIBRUS_SYNERGIA }, + requiredLoginMethod = { _, loginStore -> + if (loginStore.mode == LoginMode.LIBRUS_EMAIL) LIBRUS_PORTAL + else null + }, + ), + LIBRUS_SYNERGIA( + loginType = LoginType.LIBRUS, + id = 2300, + isPossible = { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }, + requiredLoginMethod = { _, _ -> LIBRUS_API }, + ), + LIBRUS_MESSAGES( + loginType = LoginType.LIBRUS, + id = 2400, + isPossible = { _, loginStore -> !loginStore.hasLoginData("fakeLogin") }, + requiredLoginMethod = { _, _ -> LIBRUS_SYNERGIA }, + ), + VULCAN_WEB_MAIN( + loginType = LoginType.VULCAN, + id = 4100, + isPossible = { _, loginStore -> loginStore.hasLoginData("webHost") }, + ), + VULCAN_HEBE( + loginType = LoginType.VULCAN, + id = 4600, + isPossible = { _, loginStore -> loginStore.mode != LoginMode.VULCAN_API }, + ), + PODLASIE_API( + loginType = LoginType.PODLASIE, + id = 6100, + ), + USOS_API( + loginType = LoginType.USOS, + id = 7100, + ), + TEMPLATE_WEB( + loginType = LoginType.TEMPLATE, + id = 21100, + ), + TEMPLATE_API( + loginType = LoginType.TEMPLATE, + id = 21200, + requiredLoginMethod = { _, _ -> TEMPLATE_WEB }, + ), +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMode.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMode.kt new file mode 100644 index 00000000..9deb5310 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginMode.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +enum class LoginMode( + val loginType: LoginType, + val id: Int, +) { + MOBIDZIENNIK_WEB(LoginType.MOBIDZIENNIK, id = 100), + LIBRUS_EMAIL(LoginType.LIBRUS, id = 200), + LIBRUS_SYNERGIA(LoginType.LIBRUS, id = 201), + LIBRUS_JST(LoginType.LIBRUS, id = 202), + VULCAN_API(LoginType.VULCAN, id = 400), + VULCAN_WEB(LoginType.VULCAN, id = 401), + VULCAN_HEBE(LoginType.VULCAN, id = 402), + PODLASIE_API(LoginType.PODLASIE, id = 600), + USOS_OAUTH(LoginType.USOS, id = 700), +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt new file mode 100644 index 00000000..ea77dd7c --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType.* + +private val FEATURES_BASE = listOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, +) +private val FEATURES_EXTENDED = listOf( + BEHAVIOUR, + ATTENDANCE, +) +private val FEATURES_MESSAGES = listOf( + MESSAGES_INBOX, + MESSAGES_SENT, +) + +enum class LoginType( + val id: Int, + val features: List, +) { + MOBIDZIENNIK(id = 1, features = FEATURES_BASE + FEATURES_EXTENDED + FEATURES_MESSAGES), + LIBRUS(id = 2, features = MOBIDZIENNIK.features + ANNOUNCEMENTS), + VULCAN(id = 4, features = MOBIDZIENNIK.features), + PODLASIE(id = 6, features = FEATURES_BASE), + USOS(id = 7, features = FEATURES_BASE - GRADES), + DEMO(id = 20, features = listOf()), + TEMPLATE(id = 21, features = listOf()), + + // the graveyard + EDUDZIENNIK(id = 5, features = FEATURES_BASE + FEATURES_EXTENDED), + IDZIENNIK(id = 3, features = LIBRUS.features), +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/MetadataType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/MetadataType.kt new file mode 100644 index 00000000..a993820f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/MetadataType.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +enum class MetadataType( + val id: Int, +) { + GRADE(id = 1), + NOTICE(id = 2), + ATTENDANCE(id = 3), + EVENT(id = 4), + HOMEWORK(id = 5), + LESSON_CHANGE(id = 6), + ANNOUNCEMENT(id = 7), + MESSAGE(id = 8), + TEACHER_ABSENCE(id = 9), + LUCKY_NUMBER(id = 10), +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/NotificationType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/NotificationType.kt new file mode 100644 index 00000000..4b6842d9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/NotificationType.kt @@ -0,0 +1,134 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-20. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import pl.szczodrzynski.edziennik.R + +enum class NotificationType( + val id: Int, + val icon: IIcon = CommunityMaterial.Icon.cmd_bell_ring_outline, + val titleRes: Int, + val pluralRes: Int = R.plurals.notification_other_format, + val enabledByDefault: Boolean? = true, +) { + TIMETABLE_LESSON_CHANGE( + id = 4, + icon = CommunityMaterial.Icon3.cmd_timetable, + titleRes = R.string.notification_type_timetable_lesson_change, + pluralRes = R.plurals.notification_new_timetable_change_format, + ), + GRADE( + id = 5, + icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline, + titleRes = R.string.notification_type_new_grade, + pluralRes = R.plurals.notification_new_grades_format, + ), + EVENT( + id = 6, + icon = CommunityMaterial.Icon.cmd_calendar_outline, + titleRes = R.string.notification_type_new_event, + pluralRes = R.plurals.notification_new_events_format, + ), + HOMEWORK( + id = 10, + icon = CommunityMaterial.Icon3.cmd_notebook_outline, + titleRes = R.string.notification_type_new_homework, + pluralRes = R.plurals.notification_new_homework_format, + ), + MESSAGE( + id = 8, + icon = CommunityMaterial.Icon.cmd_email_outline, + titleRes = R.string.notification_type_new_message, + pluralRes = R.plurals.notification_new_messages_format, + ), + LUCKY_NUMBER( + id = 14, + icon = CommunityMaterial.Icon.cmd_emoticon_excited_outline, + titleRes = R.string.notification_type_lucky_number, + pluralRes = R.plurals.notification_new_lucky_number_format, + ), + NOTICE( + id = 9, + icon = CommunityMaterial.Icon.cmd_emoticon_outline, + titleRes = R.string.notification_type_notice, + pluralRes = R.plurals.notification_new_notices_format, + ), + ATTENDANCE( + id = 13, + icon = CommunityMaterial.Icon.cmd_calendar_remove_outline, + titleRes = R.string.notification_type_attendance, + pluralRes = R.plurals.notification_new_attendance_format, + ), + ANNOUNCEMENT( + id = 15, + icon = CommunityMaterial.Icon.cmd_bullhorn_outline, + titleRes = R.string.notification_type_feedback_message, + pluralRes = R.plurals.notification_new_announcements_format, + ), + SHARED_EVENT( + id = 7, + icon = CommunityMaterial.Icon.cmd_calendar_outline, + titleRes = R.string.notification_type_new_shared_event, + pluralRes = R.plurals.notification_new_shared_events_format, + ), + SHARED_HOMEWORK( + id = 12, + icon = CommunityMaterial.Icon3.cmd_notebook_outline, + titleRes = R.string.notification_type_new_shared_homework, + pluralRes = R.plurals.notification_new_shared_homework_format, + ), + SHARED_NOTE( + id = 20, + icon = CommunityMaterial.Icon3.cmd_playlist_edit, + titleRes = R.string.notification_type_new_shared_note, + ), + REMOVED_SHARED_EVENT( + id = 18, + titleRes = R.string.notification_type_removed_shared_event, + ), + TEACHER_ABSENCE( + id = 19, + titleRes = R.string.notification_type_new_teacher_absence, + enabledByDefault = false, + ), + + GENERAL( + id = 0, + titleRes = R.string.notification_type_general, + enabledByDefault = null, + ), + UPDATE( + id = 1, + titleRes = R.string.notification_type_update, + enabledByDefault = null, + ), + ERROR( + id = 2, + titleRes = R.string.notification_type_error, + enabledByDefault = null, + ), + TIMETABLE_CHANGED( + id = 3, + titleRes = R.string.notification_type_timetable_change, + enabledByDefault = null, + ), + SERVER_MESSAGE( + id = 11, + titleRes = R.string.notification_type_server_message, + enabledByDefault = null, + ), + FEEDBACK_MESSAGE( + id = 16, + titleRes = R.string.notification_type_feedback_message, + enabledByDefault = null, + ), + AUTO_ARCHIVING( + id = 17, + titleRes = R.string.notification_type_auto_archiving, + enabledByDefault = null, + ), +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration58.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration58.kt index d0ebf548..ba1f26b7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration58.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration58.kt @@ -6,14 +6,13 @@ package pl.szczodrzynski.edziennik.data.db.migration import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_EVENT -import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_HOMEWORK +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class Migration58 : Migration(57, 58) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE metadata RENAME TO _metadata_old;") database.execSQL("DROP INDEX index_metadata_profileId_thingType_thingId;") - database.execSQL("UPDATE _metadata_old SET thingType = $TYPE_HOMEWORK WHERE thingType = $TYPE_EVENT AND thingId IN (SELECT eventId FROM events WHERE eventType = -1)") + database.execSQL("UPDATE _metadata_old SET thingType = ${MetadataType.HOMEWORK.id} WHERE thingType = ${MetadataType.EVENT.id} AND thingId IN (SELECT eventId FROM events WHERE eventType = -1)") database.execSQL("""CREATE TABLE metadata ( profileId INTEGER NOT NULL, metadataId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration68.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration68.kt index f7a079d0..6bbc8e86 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration68.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration68.kt @@ -6,12 +6,12 @@ package pl.szczodrzynski.edziennik.data.db.migration import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ANNOUNCEMENT +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class Migration68 : Migration(67, 68) { override fun migrate(database: SupportSQLiteDatabase) { /* Migration from crc16 to crc32 id */ database.execSQL("DELETE FROM announcements") - database.execSQL("DELETE FROM metadata WHERE thingType=$TYPE_ANNOUNCEMENT") + database.execSQL("DELETE FROM metadata WHERE thingType=${MetadataType.ANNOUNCEMENT.id}") } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration71.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration71.kt index dabb2303..5166a0ce 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration71.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration71.kt @@ -6,7 +6,7 @@ package pl.szczodrzynski.edziennik.data.db.migration import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_MESSAGE +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class Migration71 : Migration(70, 71) { override fun migrate(database: SupportSQLiteDatabase) { @@ -14,7 +14,7 @@ class Migration71 : Migration(70, 71) { database.execSQL("DELETE FROM messageRecipients WHERE profileId IN (SELECT profileId FROM profiles WHERE archived = 0)") database.execSQL("DELETE FROM teachers WHERE profileId IN (SELECT profileId FROM profiles WHERE archived = 0)") database.execSQL("DELETE FROM endpointTimers WHERE profileId IN (SELECT profileId FROM profiles WHERE archived = 0)") - database.execSQL("DELETE FROM metadata WHERE profileId IN (SELECT profileId FROM profiles WHERE archived = 0) AND thingType = $TYPE_MESSAGE") + database.execSQL("DELETE FROM metadata WHERE profileId IN (SELECT profileId FROM profiles WHERE archived = 0) AND thingType = ${MetadataType.MESSAGE.id}") database.execSQL("UPDATE profiles SET empty = 1 WHERE archived = 0") database.execSQL("UPDATE profiles SET lastReceiversSync = 0 WHERE archived = 0") database.execSQL("INSERT INTO config (profileId, `key`, value) VALUES (-1, 'runSync', 'true')") diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration81.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration81.kt index bf547244..5af06357 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration81.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration81.kt @@ -2,10 +2,10 @@ package pl.szczodrzynski.edziennik.data.db.migration import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType class Migration81 : Migration(80, 81) { override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("UPDATE metadata SET seen = 1, notified = 1 WHERE thingType = ${Metadata.TYPE_TEACHER_ABSENCE}") + database.execSQL("UPDATE metadata SET seen = 1, notified = 1 WHERE thingType = ${MetadataType.TEACHER_ABSENCE.id}") } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration85.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration85.kt index 6f1c79c0..b53c08e2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration85.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration85.kt @@ -2,11 +2,11 @@ package pl.szczodrzynski.edziennik.data.db.migration import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_EDUDZIENNIK import pl.szczodrzynski.edziennik.data.db.entity.Event +import pl.szczodrzynski.edziennik.data.db.enums.LoginType class Migration85 : Migration(84, 85) { override fun migrate(database: SupportSQLiteDatabase) { - database.execSQL("DELETE FROM events WHERE eventAddedManually = 0 AND eventType = ${Event.TYPE_HOMEWORK} AND profileId IN (SELECT profileId FROM (SELECT profileId FROM profiles WHERE loginStoreType = $LOGIN_TYPE_EDUDZIENNIK) x)") + database.execSQL("DELETE FROM events WHERE eventAddedManually = 0 AND eventType = ${Event.TYPE_HOMEWORK} AND profileId IN (SELECT profileId FROM (SELECT profileId FROM profiles WHERE loginStoreType = ${LoginType.EDUDZIENNIK.id}) x)") } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration94.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration94.kt index 84df9c59..1facd564 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration94.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration94.kt @@ -7,7 +7,7 @@ package pl.szczodrzynski.edziennik.data.db.migration import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase import pl.szczodrzynski.edziennik.data.db.entity.Event -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.enums.LoginType class Migration94 : Migration(93, 94) { override fun migrate(database: SupportSQLiteDatabase) { @@ -15,7 +15,7 @@ class Migration94 : Migration(93, 94) { // get all profiles using Mobidziennik database.execSQL("CREATE TABLE _94_ids (id INTEGER NOT NULL);") - database.execSQL("INSERT INTO _94_ids SELECT profileId FROM profiles JOIN loginStores USING(loginStoreId) WHERE loginStores.loginStoreType = ${LoginStore.LOGIN_TYPE_MOBIDZIENNIK};") + database.execSQL("INSERT INTO _94_ids SELECT profileId FROM profiles JOIN loginStores USING(loginStoreId) WHERE loginStores.loginStoreType = ${LoginType.MOBIDZIENNIK};") database.execSQL("ALTER TABLE events ADD COLUMN eventIsDownloaded INT NOT NULL DEFAULT 1;") // set isDownloaded = 0 for information events in Mobidziennik diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration99.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration99.kt new file mode 100644 index 00000000..d321765c --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration99.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-19. + */ + +package pl.szczodrzynski.edziennik.data.db.migration + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration99 : Migration(98, 99) { + override fun migrate(database: SupportSQLiteDatabase) { + // enum refactor, part 1 - make LoginStore modes unique, even without type + database.execSQL("UPDATE loginStores SET loginStoreMode = loginStoreType * 100 + loginStoreMode;") + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyAppFirebase.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyAppFirebase.kt index 4f90ac67..9c1a248f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyAppFirebase.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyAppFirebase.kt @@ -8,18 +8,21 @@ import com.google.gson.JsonParser import com.google.gson.reflect.TypeToken import kotlinx.coroutines.* import org.greenrobot.eventbus.EventBus -import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.data.api.events.FeedbackMessageEvent import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update import pl.szczodrzynski.edziennik.data.api.task.PostNotifications import pl.szczodrzynski.edziennik.data.db.entity.* +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getLong -import pl.szczodrzynski.edziennik.ext.getNotificationTitle import pl.szczodrzynski.edziennik.ext.getString +import pl.szczodrzynski.edziennik.ext.resolveString import pl.szczodrzynski.edziennik.sync.UpdateWorker +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time import kotlin.coroutines.CoroutineContext @@ -85,7 +88,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List, val message: id = System.currentTimeMillis(), title = title, text = message, - type = Notification.TYPE_SERVER_MESSAGE, + type = NotificationType.SERVER_MESSAGE, profileId = null, profileName = title ).addExtra("action", "serverMessage").addExtra("serverMessageTitle", title).addExtra("serverMessageText", message) @@ -105,7 +108,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List, val message: id = System.currentTimeMillis(), title = "Wiadomość od ${message.senderName}", text = message.text, - type = Notification.TYPE_FEEDBACK_MESSAGE, + type = NotificationType.FEEDBACK_MESSAGE, profileId = null, profileName = "Wiadomość od ${message.senderName}" ).addExtra("action", "feedbackMessage").addExtra("feedbackMessageDeviceId", message.deviceId) @@ -155,24 +158,24 @@ class SzkolnyAppFirebase(val app: App, val profiles: List, val message: val metadata = Metadata( event.profileId, - if (event.isHomework) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT, + if (event.isHomework) MetadataType.HOMEWORK else MetadataType.EVENT, event.id, false, true ) - val type = if (event.isHomework) Notification.TYPE_NEW_SHARED_HOMEWORK else Notification.TYPE_NEW_SHARED_EVENT + val type = if (event.isHomework) NotificationType.SHARED_HOMEWORK else NotificationType.SHARED_EVENT val notificationFilter = app.config.getFor(event.profileId).sync.notificationFilter if (!notificationFilter.contains(type) && event.sharedBy != "self" && event.date >= Date.getToday()) { val notification = Notification( id = Notification.buildId(event.profileId, type, event.id), - title = app.getNotificationTitle(type), + title = type.titleRes.resolveString(app), text = message, type = type, profileId = profile.id, profileName = profile.name, - viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA, + navTarget = if (event.isHomework) NavTarget.HOMEWORK else NavTarget.AGENDA, addedDate = event.addedDate ).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong()) notificationList += notification @@ -199,15 +202,15 @@ class SzkolnyAppFirebase(val app: App, val profiles: List, val message: return@forEach val notificationFilter = app.config.getFor(team.profileId).sync.notificationFilter - if (!notificationFilter.contains(Notification.TYPE_REMOVED_SHARED_EVENT)) { + if (!notificationFilter.contains(NotificationType.REMOVED_SHARED_EVENT)) { val notification = Notification( - id = Notification.buildId(profile.id, Notification.TYPE_REMOVED_SHARED_EVENT, eventId), - title = app.getNotificationTitle(Notification.TYPE_REMOVED_SHARED_EVENT), + id = Notification.buildId(profile.id, NotificationType.REMOVED_SHARED_EVENT, eventId), + title = NotificationType.REMOVED_SHARED_EVENT.titleRes.resolveString(app), text = message, - type = Notification.TYPE_REMOVED_SHARED_EVENT, + type = NotificationType.REMOVED_SHARED_EVENT, profileId = profile.id, profileName = profile.name, - viewId = MainActivity.DRAWER_ITEM_AGENDA + navTarget = NavTarget.AGENDA, ) notificationList += notification } @@ -250,18 +253,18 @@ class SzkolnyAppFirebase(val app: App, val profiles: List, val message: if (hadNote) return@forEach - val type = Notification.TYPE_NEW_SHARED_NOTE + val type = NotificationType.SHARED_NOTE val notificationFilter = app.config.getFor(note.profileId).sync.notificationFilter if (!notificationFilter.contains(type) && note.sharedBy != "self") { val notification = Notification( id = Notification.buildId(note.profileId, type, note.id), - title = app.getNotificationTitle(type), + title = type.titleRes.resolveString(app), text = message, type = type, profileId = profile.id, profileName = profile.name, - viewId = MainActivity.DRAWER_ITEM_HOME, + navTarget = NavTarget.HOME, addedDate = note.addedDate ).addExtra("noteId", note.id) notificationList += notification diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyLibrusFirebase.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyLibrusFirebase.kt index a9a183e5..295b53ad 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyLibrusFirebase.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyLibrusFirebase.kt @@ -5,12 +5,12 @@ package pl.szczodrzynski.edziennik.data.firebase import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.MainActivity -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.librus.* import pl.szczodrzynski.edziennik.data.api.task.IApiTask import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.getString class SzkolnyLibrusFirebase(val app: App, val profiles: List, val message: FirebaseService.Message) { @@ -31,27 +31,27 @@ class SzkolnyLibrusFirebase(val app: App, val profiles: List, val messa /* ./src/store/modules/helpers/change-processor.js */ val endpoints = when (type) { - "Notes" -> listOf(ENDPOINT_LIBRUS_API_NOTICES) - "Grades" -> listOf(ENDPOINT_LIBRUS_API_NORMAL_GRADES, ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES, ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS) - "PointGrades" -> listOf(ENDPOINT_LIBRUS_API_POINT_GRADES, ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES) - "DescriptiveGrades" -> listOf(ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES) - "DescriptiveGrades/Text/Categories" -> listOf(ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES) - "DescriptiveTextGrades" -> listOf(ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES) - "TextGrades" -> listOf(ENDPOINT_LIBRUS_API_TEXT_GRADES) - "BehaviourGrades/Points" -> listOf(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES, ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES, ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS) - "BehaviourGrades" -> listOf() - "Attendances" -> listOf(ENDPOINT_LIBRUS_API_ATTENDANCES) - "HomeWorks" -> listOf(ENDPOINT_LIBRUS_API_EVENTS) - "ParentTeacherConferences" -> listOf(ENDPOINT_LIBRUS_API_PT_MEETINGS) - "Calendars/ClassFreeDays" -> listOf(ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS) - "Calendars/TeacherFreeDays" -> listOf(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS) - "Calendars/SchoolFreeDays" -> listOf(ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS) - "Calendars/Substitutions" -> listOf(ENDPOINT_LIBRUS_API_TIMETABLES) - "HomeWorkAssignments" -> listOf(ENDPOINT_LIBRUS_API_HOMEWORK, ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK) - "SchoolNotices" -> listOf(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS) - "Messages" -> listOf(ENDPOINT_LIBRUS_MESSAGES_RECEIVED) - "LuckyNumbers" -> listOf(ENDPOINT_LIBRUS_API_LUCKY_NUMBER) - "Timetables" -> listOf(ENDPOINT_LIBRUS_API_TIMETABLES) + "Notes" -> setOf(ENDPOINT_LIBRUS_API_NOTICES) + "Grades" -> setOf(ENDPOINT_LIBRUS_API_NORMAL_GRADES, ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES, ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS) + "PointGrades" -> setOf(ENDPOINT_LIBRUS_API_POINT_GRADES, ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES) + "DescriptiveGrades" -> setOf(ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES) + "DescriptiveGrades/Text/Categories" -> setOf(ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES) + "DescriptiveTextGrades" -> setOf(ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES) + "TextGrades" -> setOf(ENDPOINT_LIBRUS_API_TEXT_GRADES) + "BehaviourGrades/Points" -> setOf(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES, ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES, ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS) + "BehaviourGrades" -> setOf() + "Attendances" -> setOf(ENDPOINT_LIBRUS_API_ATTENDANCES) + "HomeWorks" -> setOf(ENDPOINT_LIBRUS_API_EVENTS) + "ParentTeacherConferences" -> setOf(ENDPOINT_LIBRUS_API_PT_MEETINGS) + "Calendars/ClassFreeDays" -> setOf(ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS) + "Calendars/TeacherFreeDays" -> setOf(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS) + "Calendars/SchoolFreeDays" -> setOf(ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS) + "Calendars/Substitutions" -> setOf(ENDPOINT_LIBRUS_API_TIMETABLES) + "HomeWorkAssignments" -> setOf(ENDPOINT_LIBRUS_API_HOMEWORK, ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK) + "SchoolNotices" -> setOf(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS) + "Messages" -> setOf(ENDPOINT_LIBRUS_MESSAGES_RECEIVED) + "LuckyNumbers" -> setOf(ENDPOINT_LIBRUS_API_LUCKY_NUMBER) + "Timetables" -> setOf(ENDPOINT_LIBRUS_API_TIMETABLES) else -> return@run } @@ -59,10 +59,10 @@ class SzkolnyLibrusFirebase(val app: App, val profiles: List, val messa return@run val tasks = profiles.filter { - it.loginStoreType == LOGIN_TYPE_LIBRUS && + it.loginStoreType == LoginType.LIBRUS && it.getStudentData("accountLogin", "")?.replace("u", "") == accountLogin }.map { - EdziennikTask.syncProfile(it.id, listOf(MainActivity.DRAWER_ITEM_HOME to 0), onlyEndpoints = endpoints) + EdziennikTask.syncProfile(it.id, setOf(FeatureType.ALWAYS_NEEDED), onlyEndpoints = endpoints) } IApiTask.enqueueAll(app, tasks) }} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyMobidziennikFirebase.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyMobidziennikFirebase.kt index d5b6c077..ad2021e7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyMobidziennikFirebase.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyMobidziennikFirebase.kt @@ -5,15 +5,11 @@ package pl.szczodrzynski.edziennik.data.firebase import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.task.IApiTask -import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getString @@ -52,19 +48,19 @@ class SzkolnyMobidziennikFirebase(val app: App, val profiles: List, val val globalId = message.data.getLong("global_id") /* assets/www/js/push.js */ - val viewIdPair = when (type) { - "wiadOdebrana" -> DRAWER_ITEM_MESSAGES to TYPE_RECEIVED - "oceny", "ocenyKoncowe", "zachowanie" -> DRAWER_ITEM_GRADES to 0 - "uwagi" -> DRAWER_ITEM_BEHAVIOUR to 0 - "nieobecnoscPierwszaLekcja", "nieobecnosciDzisiaj" -> DRAWER_ITEM_ATTENDANCE to 0 + val featureType = when (type) { + "wiadOdebrana" -> FeatureType.MESSAGES_INBOX + "oceny", "ocenyKoncowe", "zachowanie" -> FeatureType.GRADES + "uwagi" -> FeatureType.BEHAVIOUR + "nieobecnoscPierwszaLekcja", "nieobecnosciDzisiaj" -> FeatureType.ATTENDANCE else -> return@run } val tasks = profiles.filter { - it.loginStoreType == LOGIN_TYPE_MOBIDZIENNIK && + it.loginStoreType == LoginType.MOBIDZIENNIK && it.getStudentData("globalId", 0L) == globalId }.map { - EdziennikTask.syncProfile(it.id, listOf(viewIdPair)) + EdziennikTask.syncProfile(it.id, setOf(featureType)) } IApiTask.enqueueAll(app, tasks) }} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyVulcanFirebase.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyVulcanFirebase.kt index 74ccdd85..2c33964a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyVulcanFirebase.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/firebase/SzkolnyVulcanFirebase.kt @@ -5,15 +5,15 @@ package pl.szczodrzynski.edziennik.data.firebase import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_VULCAN import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.task.IApiTask import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.toJsonObject -import java.util.* class SzkolnyVulcanFirebase(val app: App, val profiles: List, val message: FirebaseService.Message) { /*{ @@ -35,22 +35,22 @@ class SzkolnyVulcanFirebase(val app: App, val profiles: List, val messa val loginId = data.getInt("loginid") /* pl.vulcan.uonetmobile.auxilary.enums.CDCPushEnum */ - val viewIdPair = when (type.lowercase()) { - "wiadomosc" -> MainActivity.DRAWER_ITEM_MESSAGES to Message.TYPE_RECEIVED - "ocena" -> MainActivity.DRAWER_ITEM_GRADES to 0 - "uwaga" -> MainActivity.DRAWER_ITEM_BEHAVIOUR to 0 - "frekwencja" -> MainActivity.DRAWER_ITEM_ATTENDANCE to 0 + val featureType = when (type.lowercase()) { + "wiadomosc" -> FeatureType.MESSAGES_INBOX + "ocena" -> FeatureType.GRADES + "uwaga" -> FeatureType.BEHAVIOUR + "frekwencja" -> FeatureType.ATTENDANCE // this type is not even implemented in Dzienniczek+ - "sprawdzian" -> MainActivity.DRAWER_ITEM_AGENDA to 0 + "sprawdzian" -> FeatureType.AGENDA else -> return@run } val tasks = profiles.filter { - it.loginStoreType == LOGIN_TYPE_VULCAN + it.loginStoreType == LoginType.VULCAN && (it.getStudentData("studentId", 0) == studentId || it.getStudentData("studentLoginId", 0) == loginId) }.map { - EdziennikTask.syncProfile(it.id, listOf(viewIdPair)) + EdziennikTask.syncProfile(it.id, setOf(featureType)) } IApiTask.enqueueAll(app, tasks) }} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt index 037d78f5..eddcf322 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/BundleExtensions.kt @@ -9,28 +9,24 @@ import android.content.Intent import android.os.Bundle import android.os.Parcelable import com.google.gson.JsonObject +import pl.szczodrzynski.edziennik.data.db.enums.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget +import java.io.Serializable -fun Bundle?.getInt(key: String, defaultValue: Int): Int { - return this?.getInt(key, defaultValue) ?: defaultValue -} -fun Bundle?.getLong(key: String, defaultValue: Long): Long { - return this?.getLong(key, defaultValue) ?: defaultValue -} -fun Bundle?.getFloat(key: String, defaultValue: Float): Float { - return this?.getFloat(key, defaultValue) ?: defaultValue -} -fun Bundle?.getString(key: String, defaultValue: String): String { - return this?.getString(key, defaultValue) ?: defaultValue -} -inline fun > Bundle?.getEnum(key: String): E? { - return this?.getString(key)?.let { - try { - enumValueOf(it) - } catch (e: Exception) { - null - } - } -} +fun Bundle?.getInt(key: String, defaultValue: Int) = + this?.getInt(key, defaultValue) ?: defaultValue + +fun Bundle?.getLong(key: String, defaultValue: Long) = + this?.getLong(key, defaultValue) ?: defaultValue + +fun Bundle?.getFloat(key: String, defaultValue: Float) = + this?.getFloat(key, defaultValue) ?: defaultValue + +fun Bundle?.getString(key: String, defaultValue: String) = + this?.getString(key, defaultValue) ?: defaultValue + +inline fun > Bundle?.getEnum(key: String) = this?.getInt(key)?.toEnum() +fun Bundle.putEnum(key: String, value: Enum<*>) = putInt(key, value.toInt()) fun Bundle?.getIntOrNull(key: String): Int? { return this?.get(key) as? Int @@ -45,30 +41,37 @@ fun Bundle?.get(key: String): T? { fun Bundle(vararg properties: Pair): Bundle { return Bundle().apply { for (property in properties) { - when (property.second) { - is String -> putString(property.first, property.second as String?) - is Char -> putChar(property.first, property.second as Char) - is Int -> putInt(property.first, property.second as Int) - is Long -> putLong(property.first, property.second as Long) - is Float -> putFloat(property.first, property.second as Float) - is Short -> putShort(property.first, property.second as Short) - is Double -> putDouble(property.first, property.second as Double) - is Boolean -> putBoolean(property.first, property.second as Boolean) - is Bundle -> putBundle(property.first, property.second as Bundle) - is Parcelable -> putParcelable(property.first, property.second as Parcelable) - is Array<*> -> putParcelableArray(property.first, property.second as Array) - is Enum<*> -> putString(property.first, (property.second as Enum<*>).name) + val (key, value) = property + when (value) { + is String -> putString(key, value as String?) + is Char -> putChar(key, value) + is Int -> putInt(key, value) + is Long -> putLong(key, value) + is Float -> putFloat(key, value) + is Short -> putShort(key, value) + is Double -> putDouble(key, value) + is Boolean -> putBoolean(key, value) + is Bundle -> putBundle(key, value) + is Enum<*> -> putEnum(key, value) + is Array<*> -> putParcelableArray(key, value as Array) + is Parcelable -> putParcelable(key, value) + is Serializable -> putSerializable(key, value) } } } } + fun Intent(action: String? = null, vararg properties: Pair): Intent { return Intent(action).putExtras(Bundle(*properties)) } + fun Intent(packageContext: Context, cls: Class<*>, vararg properties: Pair): Intent { return Intent(packageContext, cls).putExtras(Bundle(*properties)) } +fun Intent.putExtras(vararg properties: Pair) = putExtras(Bundle(*properties)) +fun Bundle.putExtras(vararg properties: Pair) = putAll(Bundle(*properties)) + fun Bundle.toJsonObject(): JsonObject { val json = JsonObject() keySet()?.forEach { key -> @@ -89,4 +92,5 @@ fun Bundle.toJsonObject(): JsonObject { } return json } + fun Intent.toJsonObject() = extras?.toJsonObject() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt index b1e99c43..5f41af98 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt @@ -41,33 +41,6 @@ operator fun Profile.set(key: String, value: String?) = this.studentData.addProp operator fun Profile.set(key: String, value: Number) = this.studentData.addProperty(key, value) operator fun Profile.set(key: String, value: Char) = this.studentData.addProperty(key, value) -fun Context.getNotificationTitle(type: Int): String { - return getString(when (type) { - Notification.TYPE_UPDATE -> R.string.notification_type_update - Notification.TYPE_ERROR -> R.string.notification_type_error - Notification.TYPE_TIMETABLE_CHANGED -> R.string.notification_type_timetable_change - Notification.TYPE_TIMETABLE_LESSON_CHANGE -> R.string.notification_type_timetable_lesson_change - Notification.TYPE_NEW_GRADE -> R.string.notification_type_new_grade - Notification.TYPE_NEW_EVENT -> R.string.notification_type_new_event - Notification.TYPE_NEW_HOMEWORK -> R.string.notification_type_new_homework - Notification.TYPE_NEW_SHARED_EVENT -> R.string.notification_type_new_shared_event - Notification.TYPE_NEW_SHARED_HOMEWORK -> R.string.notification_type_new_shared_homework - Notification.TYPE_REMOVED_SHARED_EVENT -> R.string.notification_type_removed_shared_event - Notification.TYPE_NEW_MESSAGE -> R.string.notification_type_new_message - Notification.TYPE_NEW_NOTICE -> R.string.notification_type_notice - Notification.TYPE_NEW_ATTENDANCE -> R.string.notification_type_attendance - Notification.TYPE_SERVER_MESSAGE -> R.string.notification_type_server_message - Notification.TYPE_LUCKY_NUMBER -> R.string.notification_type_lucky_number - Notification.TYPE_FEEDBACK_MESSAGE -> R.string.notification_type_feedback_message - Notification.TYPE_NEW_ANNOUNCEMENT -> R.string.notification_type_new_announcement - Notification.TYPE_AUTO_ARCHIVING -> R.string.notification_type_auto_archiving - Notification.TYPE_TEACHER_ABSENCE -> R.string.notification_type_new_teacher_absence - Notification.TYPE_GENERAL -> R.string.notification_type_general - Notification.TYPE_NEW_SHARED_NOTE -> R.string.notification_type_new_shared_note - else -> R.string.notification_type_general - }) -} - fun Profile.getSchoolYearConstrains(): CalendarConstraints { return CalendarConstraints.Builder() .setStart(dateSemester1Start.inMillisUtc) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/EnumExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/EnumExtensions.kt new file mode 100644 index 00000000..30b33dd9 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/EnumExtensions.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.ext + +import android.view.View +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.data.db.enums.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget +import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem + +fun Int.asFeatureType() = FeatureType.values().first { it.id == this } +fun Int.asLoginMethod() = LoginMethod.values().first { it.id == this } +fun Int.asLoginMode() = LoginMode.values().first { it.id == this } +fun Int.asLoginType() = LoginType.values().first { it.id == this } +fun Int.asMetadataType() = MetadataType.values().first { it.id == this } +fun Int.asNotificationType() = NotificationType.values().first { it.id == this } +fun Int.asNavTarget() = NavTarget.values().first { it.id == this } + +fun Int?.asFeatureTypeOrNull() = FeatureType.values().firstOrNull { it.id == this } +fun Int?.asLoginMethodOrNull() = LoginMethod.values().firstOrNull { it.id == this } +fun Int?.asLoginModeOrNull() = LoginMode.values().firstOrNull { it.id == this } +fun Int?.asLoginTypeOrNull() = LoginType.values().firstOrNull { it.id == this } +fun Int?.asMetadataTypeOrNull() = MetadataType.values().firstOrNull { it.id == this } +fun Int?.asNotificationTypeOrNull() = NotificationType.values().firstOrNull { it.id == this } +fun Int?.asNavTargetOrNull() = NavTarget.values().firstOrNull { it.id == this } + +fun Enum<*>.toInt() = when (this) { + is FeatureType -> this.id + is LoginMethod -> this.id + is LoginMode -> this.id + is LoginType -> this.id + is MetadataType -> this.id + is NotificationType -> this.id + is NavTarget -> this.id + else -> this.ordinal +} + +inline fun > Int.toEnum() = when (E::class.java) { + // enums commented out are not really used in Bundles + FeatureType::class.java -> this.asFeatureType() + // LoginMethod::class.java -> this.asLoginMethod() + LoginMode::class.java -> this.asLoginMode() + LoginType::class.java -> this.asLoginType() + // MetadataType::class.java -> this.asMetadataType() + // NotificationType::class.java -> this.asNotificationType() + NavTarget::class.java -> this.asNavTarget() + else -> enumValues()[this] +} as E + +fun > Int.toEnum(type: Class<*>) = when (type) { + // enums commented out are not really used in Bundles + FeatureType::class.java -> this.asFeatureType() + // LoginMethod::class.java -> this.asLoginMethod() + LoginMode::class.java -> this.asLoginMode() + LoginType::class.java -> this.asLoginType() + // MetadataType::class.java -> this.asMetadataType() + // NotificationType::class.java -> this.asNotificationType() + NavTarget::class.java -> this.asNavTarget() + else -> throw IllegalArgumentException("Unknown type $type") +} as E + +fun getFeatureTypesNecessary() = FeatureType.values().filter { it.isAlwaysNeeded }.toSet() +fun getFeatureTypesUnnecessary() = FeatureType.values().filter { !it.isAlwaysNeeded }.toSet() + +fun NavTarget.toBottomSheetItem(activity: MainActivity) = + BottomSheetPrimaryItem(isContextual = false).also { + it.titleRes = this.nameRes + if (this.icon != null) + it.iconicsIcon = this.icon + it.onClickListener = View.OnClickListener { + activity.navigate(navTarget = this) + } + } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt index 14d25b48..813b16c2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt @@ -42,6 +42,9 @@ fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?. fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null } fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null } +inline fun > JsonObject?.getEnum(key: String) = this?.getInt(key)?.toEnum() +fun JsonObject.putEnum(key: String, value: Enum<*>) = addProperty(key, value.toInt()) + fun String.toJsonObject(): JsonObject? = try { JsonParser.parseString(this).asJsonObject } catch (ignore: Exception) { null } operator fun JsonObject.set(key: String, value: JsonElement) = this.add(key, value) @@ -55,12 +58,14 @@ fun JsonArray.asJsonObjectList() = this.mapNotNull { it.asJsonObject } fun JsonObject(vararg properties: Pair): JsonObject { return JsonObject().apply { for (property in properties) { - when (property.second) { - is JsonElement -> add(property.first, property.second as JsonElement?) - is String -> addProperty(property.first, property.second as String?) - is Char -> addProperty(property.first, property.second as Char?) - is Number -> addProperty(property.first, property.second as Number?) - is Boolean -> addProperty(property.first, property.second as Boolean?) + val (key, value) = property + when (value) { + is JsonElement -> add(key, value) + is String -> addProperty(key, value) + is Char -> addProperty(key, value) + is Number -> addProperty(key, value) + is Boolean -> addProperty(key, value) + is Enum<*> -> addProperty(key, value.toInt()) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/AgendaFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/AgendaFragment.kt index 83d89e67..7d96a14d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/AgendaFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/AgendaFragment.kt @@ -24,6 +24,7 @@ import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.EventType import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding import pl.szczodrzynski.edziennik.ui.dialogs.settings.AgendaConfigDialog @@ -105,7 +106,7 @@ class AgendaFragment : Fragment(), CoroutineScope { activity.bottomSheet.close() withContext(Dispatchers.Default) { App.db.metadataDao() - .setAllSeen(app.profileId, Metadata.TYPE_EVENT, true) + .setAllSeen(app.profileId, MetadataType.EVENT, true) } Toast.makeText( activity, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/announcements/AnnouncementsFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/announcements/AnnouncementsFragment.java index 3eadad95..69f29693 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/announcements/AnnouncementsFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/announcements/AnnouncementsFragment.java @@ -1,8 +1,6 @@ package pl.szczodrzynski.edziennik.ui.announcements; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; -import static pl.szczodrzynski.edziennik.data.db.entity.LoginStore.LOGIN_TYPE_LIBRUS; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_ANNOUNCEMENT; import android.os.AsyncTask; import android.os.Bundle; @@ -30,6 +28,8 @@ import pl.szczodrzynski.edziennik.MainActivity; import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask; import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent; +import pl.szczodrzynski.edziennik.data.db.enums.LoginType; +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType; import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull; import pl.szczodrzynski.edziennik.databinding.DialogAnnouncementBinding; import pl.szczodrzynski.edziennik.databinding.FragmentAnnouncementsBinding; @@ -69,10 +69,10 @@ public class AnnouncementsFragment extends Fragment { .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) .withOnClickListener(v3 -> { activity.getBottomSheet().close(); - if (app.getProfile().getLoginStoreType() == LOGIN_TYPE_LIBRUS) { + if (app.getProfile().getLoginStoreType() == LoginType.LIBRUS) { EdziennikTask.Companion.announcementsRead(App.Companion.getProfileId()).enqueue(requireContext()); } else { - AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_ANNOUNCEMENT, true)); + AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), MetadataType.ANNOUNCEMENT, true)); Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show(); } }) @@ -103,7 +103,7 @@ public class AnnouncementsFragment extends Fragment { } }); - app.db.announcementDao().getAll(App.Companion.getProfileId()).observe(this, announcements -> { + app.db.announcementDao().getAll(App.Companion.getProfileId()).observe(getViewLifecycleOwner(), announcements -> { if (app == null || activity == null || b == null || !isAdded()) return; @@ -124,7 +124,7 @@ public class AnnouncementsFragment extends Fragment { return; }*/ AnnouncementsAdapter announcementsAdapter = new AnnouncementsAdapter(activity, announcements, (v, announcement) -> { - if (announcement.getText() == null || (app.getProfile().getLoginStoreType() == LOGIN_TYPE_LIBRUS && !announcement.getSeen())) { + if (announcement.getText() == null || (app.getProfile().getLoginStoreType() == LoginType.LIBRUS && !announcement.getSeen())) { EdziennikTask.Companion.announcementGet(App.Companion.getProfileId(), announcement).enqueue(requireContext()); } else { showAnnouncementDetailsDialog(announcement); @@ -172,7 +172,7 @@ public class AnnouncementsFragment extends Fragment { .setPositiveButton(R.string.ok, null) .show(); b.text.setText(announcement.getTeacherName() +"\n\n"+ (announcement.getStartDate() != null ? announcement.getStartDate().getFormattedString() : "-") + (announcement.getEndDate() != null ? " do " + announcement.getEndDate().getFormattedString() : "")+"\n\n" +announcement.getText()); - if (!announcement.getSeen() && app.getProfile().getLoginStoreType() != LOGIN_TYPE_LIBRUS) { + if (!announcement.getSeen() && app.getProfile().getLoginStoreType() != LoginType.LIBRUS) { announcement.setSeen(true); AsyncTask.execute(() -> App.db.metadataDao().setSeen(App.Companion.getProfileId(), announcement, true)); if (recyclerView.getAdapter() != null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/attendance/AttendanceFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/attendance/AttendanceFragment.kt index e5687a3c..0f2dc065 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/attendance/AttendanceFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/attendance/AttendanceFragment.kt @@ -19,6 +19,7 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.databinding.AttendanceFragmentBinding import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.addOnPageSelectedListener @@ -75,7 +76,7 @@ class AttendanceFragment : Fragment(), CoroutineScope { .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() - AsyncTask.execute { App.db.metadataDao().setAllSeen(App.profileId, Metadata.TYPE_ATTENDANCE, true) } + AsyncTask.execute { App.db.metadataDao().setAllSeen(App.profileId, MetadataType.ATTENDANCE, true) } Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show() }) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTarget.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTarget.kt new file mode 100644 index 00000000..a62ecf7c --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTarget.kt @@ -0,0 +1,242 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.ui.base.enums + +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment +import com.mikepenz.iconics.typeface.IIcon +import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial +import eu.szkolny.font.SzkolnyFont +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType +import pl.szczodrzynski.edziennik.ui.agenda.AgendaFragment +import pl.szczodrzynski.edziennik.ui.announcements.AnnouncementsFragment +import pl.szczodrzynski.edziennik.ui.attendance.AttendanceFragment +import pl.szczodrzynski.edziennik.ui.behaviour.BehaviourFragment +import pl.szczodrzynski.edziennik.ui.debug.DebugFragment +import pl.szczodrzynski.edziennik.ui.debug.LabFragment +import pl.szczodrzynski.edziennik.ui.feedback.FeedbackFragment +import pl.szczodrzynski.edziennik.ui.grades.GradesListFragment +import pl.szczodrzynski.edziennik.ui.grades.editor.GradesEditorFragment +import pl.szczodrzynski.edziennik.ui.home.HomeFragment +import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment +import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment +import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment +import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment +import pl.szczodrzynski.edziennik.ui.notes.NotesFragment +import pl.szczodrzynski.edziennik.ui.notifications.NotificationsListFragment +import pl.szczodrzynski.edziennik.ui.settings.ProfileManagerFragment +import pl.szczodrzynski.edziennik.ui.settings.SettingsFragment +import pl.szczodrzynski.edziennik.ui.teachers.TeachersListFragment +import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment +import pl.szczodrzynski.edziennik.ui.webpush.WebPushFragment + +enum class NavTarget( + val id: Int, + val fragmentClass: Class?, + val location: NavTargetLocation = NavTargetLocation.NOWHERE, + @StringRes val nameRes: Int, + @StringRes val descriptionRes: Int? = null, + @StringRes val titleRes: Int? = null, + val icon: IIcon? = null, + val popTo: NavTarget? = null, + val badgeType: MetadataType? = null, + val featureType: FeatureType? = null, + val devModeOnly: Boolean = false, +) { + HOME( + id = 1, + fragmentClass = HomeFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_home_page, + titleRes = R.string.app_name, + icon = CommunityMaterial.Icon2.cmd_home_outline, + ), + TIMETABLE( + id = 11, + fragmentClass = TimetableFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_timetable, + icon = CommunityMaterial.Icon3.cmd_timetable, + popTo = HOME, + badgeType = MetadataType.LESSON_CHANGE, + featureType = FeatureType.TIMETABLE, + ), + AGENDA( + id = 12, + fragmentClass = AgendaFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_agenda, + icon = CommunityMaterial.Icon.cmd_calendar_outline, + popTo = HOME, + badgeType = MetadataType.EVENT, + featureType = FeatureType.AGENDA, + ), + GRADES( + id = 13, + fragmentClass = GradesListFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_grades, + icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline, + popTo = HOME, + badgeType = MetadataType.GRADE, + featureType = FeatureType.GRADES, + ), + MESSAGES( + id = 17, + fragmentClass = MessagesFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_messages, + icon = CommunityMaterial.Icon.cmd_email_outline, + popTo = HOME, + badgeType = MetadataType.MESSAGE, + featureType = FeatureType.MESSAGES_INBOX, + ), + HOMEWORK( + id = 14, + fragmentClass = HomeworkFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_homework, + icon = SzkolnyFont.Icon.szf_notebook_outline, + popTo = HOME, + badgeType = MetadataType.HOMEWORK, + featureType = FeatureType.HOMEWORK, + ), + BEHAVIOUR( + id = 15, + fragmentClass = BehaviourFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_notices, + icon = CommunityMaterial.Icon.cmd_emoticon_outline, + popTo = HOME, + badgeType = MetadataType.NOTICE, + featureType = FeatureType.BEHAVIOUR, + ), + ATTENDANCE( + id = 16, + fragmentClass = AttendanceFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_attendance, + icon = CommunityMaterial.Icon.cmd_calendar_remove_outline, + popTo = HOME, + badgeType = MetadataType.ATTENDANCE, + featureType = FeatureType.ATTENDANCE, + ), + ANNOUNCEMENTS( + id = 18, + fragmentClass = AnnouncementsFragment::class.java, + location = NavTargetLocation.DRAWER, + nameRes = R.string.menu_announcements, + icon = CommunityMaterial.Icon.cmd_bullhorn_outline, + popTo = HOME, + badgeType = MetadataType.ANNOUNCEMENT, + featureType = FeatureType.ANNOUNCEMENTS, + ), + NOTES( + id = 23, + fragmentClass = NotesFragment::class.java, + location = NavTargetLocation.DRAWER_MORE, + nameRes = R.string.menu_notes, + icon = CommunityMaterial.Icon3.cmd_text_box_multiple_outline, + ), + TEACHERS( + id = 22, + fragmentClass = TeachersListFragment::class.java, + location = NavTargetLocation.DRAWER_MORE, + nameRes = R.string.menu_teachers, + icon = CommunityMaterial.Icon3.cmd_shield_account_outline, + ), + NOTIFICATIONS( + id = 20, + fragmentClass = NotificationsListFragment::class.java, + location = NavTargetLocation.DRAWER_BOTTOM, + nameRes = R.string.menu_notifications, + icon = CommunityMaterial.Icon.cmd_bell_ring_outline, + popTo = HOME, + ), + SETTINGS( + id = 101, + fragmentClass = SettingsFragment::class.java, + location = NavTargetLocation.DRAWER_BOTTOM, + nameRes = R.string.menu_settings, + icon = CommunityMaterial.Icon.cmd_cog_outline, + ), + LAB( + id = 1000, + fragmentClass = LabFragment::class.java, + location = NavTargetLocation.DRAWER_BOTTOM, + nameRes = R.string.menu_lab, + icon = CommunityMaterial.Icon2.cmd_flask_outline, + popTo = HOME, + devModeOnly = true, + ), + PROFILE_ADD( + id = 200, + fragmentClass = null, + location = NavTargetLocation.PROFILE_LIST, + nameRes = R.string.menu_add_new_profile, + descriptionRes = R.string.drawer_add_new_profile_desc, + icon = CommunityMaterial.Icon3.cmd_plus, + ), + PROFILE_MANAGER( + id = 203, + fragmentClass = ProfileManagerFragment::class.java, + location = NavTargetLocation.NOWHERE, + nameRes = R.string.menu_manage_profiles, + titleRes = R.string.title_profile_manager, + descriptionRes = R.string.drawer_manage_profiles_desc, + icon = CommunityMaterial.Icon.cmd_account_group, + ), + PROFILE_MARK_AS_READ( + id = 204, + fragmentClass = null, + location = NavTargetLocation.PROFILE_LIST, + nameRes = R.string.menu_mark_everything_as_read, + icon = CommunityMaterial.Icon.cmd_eye_check_outline, + ), + PROFILE_SYNC_ALL( + id = 201, + fragmentClass = null, + location = NavTargetLocation.PROFILE_LIST, + nameRes = R.string.menu_sync_all, + icon = CommunityMaterial.Icon.cmd_download_outline, + ), + FEEDBACK( + id = 120, + fragmentClass = FeedbackFragment::class.java, + location = NavTargetLocation.BOTTOM_SHEET, + nameRes = R.string.menu_feedback, + icon = CommunityMaterial.Icon2.cmd_help_circle_outline, + ), + DEBUG( + id = 102, + fragmentClass = DebugFragment::class.java, + location = NavTargetLocation.BOTTOM_SHEET, + nameRes = R.string.menu_debug, + icon = CommunityMaterial.Icon.cmd_android_debug_bridge, + ), + GRADES_EDITOR( + id = 501, + fragmentClass = GradesEditorFragment::class.java, + nameRes = R.string.menu_grades_editor, + ), + MESSAGE( + id = 503, + fragmentClass = MessageFragment::class.java, + nameRes = R.string.menu_message, + popTo = MESSAGES, + ), + MESSAGE_COMPOSE( + id = 504, + fragmentClass = MessagesComposeFragment::class.java, + nameRes = R.string.menu_message_compose, + ), + WEB_PUSH( + id = 140, + fragmentClass = WebPushFragment::class.java, + nameRes = R.string.menu_web_push, + ) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTargetLocation.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTargetLocation.kt new file mode 100644 index 00000000..24ab9134 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/base/enums/NavTargetLocation.kt @@ -0,0 +1,14 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-17. + */ + +package pl.szczodrzynski.edziennik.ui.base.enums + +enum class NavTargetLocation { + NOWHERE, + DRAWER, + DRAWER_MORE, + DRAWER_BOTTOM, + PROFILE_LIST, + BOTTOM_SHEET, +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/BehaviourFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/BehaviourFragment.java index ea388d00..fef48d3c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/BehaviourFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/BehaviourFragment.java @@ -1,7 +1,6 @@ package pl.szczodrzynski.edziennik.ui.behaviour; import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_NOTICE; import android.graphics.Color; import android.os.AsyncTask; @@ -30,6 +29,7 @@ import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.MainActivity; import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.data.db.entity.Notice; +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType; import pl.szczodrzynski.edziennik.data.db.full.NoticeFull; import pl.szczodrzynski.edziennik.databinding.FragmentBehaviourBinding; import pl.szczodrzynski.edziennik.utils.Themes; @@ -72,7 +72,7 @@ public class BehaviourFragment extends Fragment { .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) .withOnClickListener(v3 -> { activity.getBottomSheet().close(); - AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_NOTICE, true)); + AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), MetadataType.NOTICE, true)); Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show(); }) ); @@ -111,7 +111,7 @@ public class BehaviourFragment extends Fragment { } }); - app.db.noticeDao().getAll(App.Companion.getProfileId()).observe(this, notices -> { + app.db.noticeDao().getAll(App.Companion.getProfileId()).observe(getViewLifecycleOwner(), notices -> { if (app == null || activity == null || b == null || !isAdded()) return; diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/NoticesAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/NoticesAdapter.kt index e37b7ed9..0d79c5ca 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/NoticesAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/behaviour/NoticesAdapter.kt @@ -18,8 +18,8 @@ import com.mikepenz.iconics.utils.sizeDp import eu.szkolny.font.SzkolnyFont import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK import pl.szczodrzynski.edziennik.data.db.entity.Notice +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.full.NoticeFull import pl.szczodrzynski.edziennik.utils.BetterLink import pl.szczodrzynski.edziennik.utils.Utils.bs @@ -40,7 +40,7 @@ class NoticesAdapter//getting the context and product list with constructor val notice = noticeList[position] - if (app.profile.loginStoreType == LOGIN_TYPE_MOBIDZIENNIK && false) { + if (app.profile.loginStoreType == LoginType.MOBIDZIENNIK && false) { holder.noticesItemReason.text = bs(null, notice.category, "\n") + notice.text holder.noticesItemTeacherName.text = app.getString(R.string.notices_points_format, notice.teacherName, if (notice.points ?: 0f > 0) "+" + notice.points else notice.points) } else { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabPageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabPageFragment.kt index aecbecb1..ed3237ab 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabPageFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabPageFragment.kt @@ -151,7 +151,7 @@ class LabPageFragment : LazyFragment(), CoroutineScope { b.profile.select(app.profileId.toLong()) b.profile.setOnChangeListener { if (activity is MainActivity) - (activity as MainActivity).loadProfile(it.id.toInt()) + (activity as MainActivity).navigate(profileId = it.id.toInt()) return@setOnChangeListener true } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabProfileFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabProfileFragment.kt index 5b289ea4..966838c2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabProfileFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/debug/LabProfileFragment.kt @@ -19,9 +19,7 @@ import kotlinx.coroutines.Job import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.databinding.TemplateListPageFragmentBinding -import pl.szczodrzynski.edziennik.ext.input -import pl.szczodrzynski.edziennik.ext.set -import pl.szczodrzynski.edziennik.ext.startCoroutineTimer +import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment import pl.szczodrzynski.edziennik.ui.login.LoginActivity import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration @@ -59,14 +57,16 @@ class LabProfileFragment : LazyFragment(), CoroutineScope { try { var parent: Any = Unit var obj: Any = Unit - var objName: String = "" + var objName = "" item.key.split(":").forEach { el -> parent = obj obj = when (el) { - "App.profile" -> app.profile - "App.profile.studentData" -> app.profile.studentData - "App.profile.loginStore" -> loginStore?.data ?: JsonObject() - "App.config" -> app.config.values + "Profile" -> app.profile + "Profile / studentData" -> app.profile.studentData + "LoginStore" -> loginStore + "LoginStore / data" -> loginStore?.data ?: JsonObject() + "Config" -> app.config.values + "Config (profile)" -> app.config.forProfile().values else -> when (obj) { is JsonObject -> (obj as JsonObject).get(el) is JsonArray -> (obj as JsonArray).get(el.toInt()) @@ -89,6 +89,7 @@ class LabProfileFragment : LazyFragment(), CoroutineScope { objVal.isBoolean -> objVal.asBoolean.toString() else -> objVal.asString } + is Enum<*> -> objVal.toInt().toString() else -> objVal.toString() } @@ -123,6 +124,7 @@ class LabProfileFragment : LazyFragment(), CoroutineScope { is String -> input is Long -> input.toLong() is Double -> input.toDouble() + is Enum<*> -> input.toInt().toEnum(objVal::class.java) else -> input } field.set(parent, newVal) @@ -130,9 +132,8 @@ class LabProfileFragment : LazyFragment(), CoroutineScope { } when (item.key.substringBefore(":")) { - "App.profile" -> app.profileSave() - "App.profile.studentData" -> app.profileSave() - "App.profile.loginStore" -> app.db.loginStoreDao().add(loginStore) + "Profile", "Profile / studentData" -> app.profileSave() + "LoginStore", "LoginStore / data" -> app.db.loginStoreDao().add(loginStore) } showJson() @@ -170,10 +171,12 @@ class LabProfileFragment : LazyFragment(), CoroutineScope { private fun showJson() { val json = JsonObject().also { json -> - json.add("App.profile", app.gson.toJsonTree(app.profile)) - json.add("App.profile.studentData", app.profile.studentData) - json.add("App.profile.loginStore", loginStore?.data ?: JsonObject()) - json.add("App.config", JsonParser.parseString(app.gson.toJson(app.config.values.toSortedMap()))) + json.add("Profile", app.gson.toJsonTree(app.profile)) + json.add("Profile / studentData", app.profile.studentData) + json.add("LoginStore", app.gson.toJsonTree(loginStore)) + json.add("LoginStore / data", loginStore?.data ?: JsonObject()) + json.add("Config", JsonParser.parseString(app.gson.toJson(app.config.values.toSortedMap()))) + json.add("Config (profile)", JsonParser.parseString(app.gson.toJson(app.config.forProfile().values.toSortedMap()))) } adapter.items = LabJsonAdapter.expand(json, 0) adapter.notifyDataSetChanged() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/ProfileRemoveDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/ProfileRemoveDialog.kt index 99d907e0..6deb0b06 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/ProfileRemoveDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/ProfileRemoveDialog.kt @@ -20,7 +20,7 @@ class ProfileRemoveDialog( val onRemove: (() -> Unit)? = null, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "ProfileRemoveDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/BaseDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/BaseDialog.kt index ba91a3f5..bfdd1687 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/BaseDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/BaseDialog.kt @@ -18,7 +18,7 @@ import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ext.setMessage import kotlin.coroutines.CoroutineContext -abstract class BaseDialog( +abstract class BaseDialog( protected val activity: AppCompatActivity, protected val onShowListener: ((tag: String) -> Unit)? = null, protected val onDismissListener: ((tag: String) -> Unit)? = null, @@ -38,8 +38,8 @@ abstract class BaseDialog( override val coroutineContext: CoroutineContext get() = job + Dispatchers.Main - private var items = emptyList() - private var itemSelected: Any? = null + private var items = emptyList() + private var itemSelected: I? = null private var itemStates = BooleanArray(0) protected open fun getTitle(): CharSequence? = null @@ -53,16 +53,16 @@ abstract class BaseDialog( open fun getNeutralButtonText(): Int? = null open fun getNegativeButtonText(): Int? = null - protected open fun getSingleChoiceItems(): Map? = null - protected open fun getMultiChoiceItems(): Map? = null - protected open fun getDefaultSelectedItem(): Any? = null - protected open fun getDefaultSelectedItems(): Set = emptySet() + protected open fun getSingleChoiceItems(): Map? = null + protected open fun getMultiChoiceItems(): Map? = null + protected open fun getDefaultSelectedItem(): I? = null + protected open fun getDefaultSelectedItems(): Set = emptySet() open suspend fun onPositiveClick() = true open suspend fun onNeutralClick() = true open suspend fun onNegativeClick() = true - open suspend fun onSingleSelectionChanged(item: Any?) = Unit - open suspend fun onMultiSelectionChanged(items: Set) = Unit + open suspend fun onSingleSelectionChanged(item: I?) = Unit + open suspend fun onMultiSelectionChanged(items: Set) = Unit protected open suspend fun onBeforeShow() = true protected abstract suspend fun onShow() @@ -184,7 +184,7 @@ abstract class BaseDialog( } protected fun getSingleSelection() = itemSelected - protected fun getMultiSelection(): Set { + protected fun getMultiSelection(): Set { return itemStates.mapIndexed { position, isChecked -> if (isChecked) items[position] diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/ViewDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/ViewDialog.kt index 17893a74..20d81b95 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/ViewDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/base/ViewDialog.kt @@ -11,7 +11,7 @@ abstract class ViewDialog( activity: AppCompatActivity, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { protected lateinit var root: V protected abstract fun getRootView(): V diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt index d9ec1631..751c91de 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/AppLanguageDialog.kt @@ -12,7 +12,7 @@ class AppLanguageDialog( activity: AppCompatActivity, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "AppLanguageDialog" override fun getTitleRes() = R.string.app_language_dialog_title diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt index 956a6b03..5a87f1ce 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/MiniMenuConfigDialog.kt @@ -5,26 +5,19 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings import androidx.appcompat.app.AppCompatActivity +import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_NOTIFICATIONS -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_SETTINGS -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.ext.resolveString +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget +import pl.szczodrzynski.edziennik.ui.base.enums.NavTargetLocation import pl.szczodrzynski.edziennik.ui.dialogs.base.BaseDialog class MiniMenuConfigDialog( activity: AppCompatActivity, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "BellSyncTimeChooseDialog" @@ -33,26 +26,23 @@ class MiniMenuConfigDialog( override fun getPositiveButtonText() = R.string.ok override fun getNegativeButtonText() = R.string.cancel - override fun getMultiChoiceItems(): Map = mapOf( - R.string.menu_home_page to DRAWER_ITEM_HOME, - R.string.menu_timetable to DRAWER_ITEM_TIMETABLE, - R.string.menu_agenda to DRAWER_ITEM_AGENDA, - R.string.menu_grades to DRAWER_ITEM_GRADES, - R.string.menu_messages to DRAWER_ITEM_MESSAGES, - R.string.menu_homework to DRAWER_ITEM_HOMEWORK, - R.string.menu_notices to DRAWER_ITEM_BEHAVIOUR, - R.string.menu_attendance to DRAWER_ITEM_ATTENDANCE, - R.string.menu_announcements to DRAWER_ITEM_ANNOUNCEMENTS, - R.string.menu_notifications to DRAWER_ITEM_NOTIFICATIONS, - R.string.menu_settings to DRAWER_ITEM_SETTINGS, - ).mapKeys { (resId, _) -> activity.getString(resId) } + @Suppress("USELESS_CAST") + override fun getMultiChoiceItems() = NavTarget.values() + .filter { + (!it.devModeOnly || App.devMode) && it.location in listOf( + NavTargetLocation.DRAWER, + // NavTargetLocation.DRAWER_MORE, + NavTargetLocation.DRAWER_BOTTOM, + ) + } + .associateBy { it.nameRes.resolveString(activity) as CharSequence } - override fun getDefaultSelectedItems() = app.config.ui.miniMenuButtons.toSet() + override fun getDefaultSelectedItems() = app.config.ui.miniMenuButtons override suspend fun onShow() = Unit override suspend fun onPositiveClick(): Boolean { - app.config.ui.miniMenuButtons = getMultiSelection().filterIsInstance() + app.config.ui.miniMenuButtons = getMultiSelection() if (activity is MainActivity) { activity.setDrawerItems() activity.drawer.updateBadges() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/NotificationFilterDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/NotificationFilterDialog.kt index 8487f8be..f77a3c18 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/NotificationFilterDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/NotificationFilterDialog.kt @@ -7,14 +7,15 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings import androidx.appcompat.app.AppCompatActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.db.entity.Notification +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType +import pl.szczodrzynski.edziennik.ext.resolveString import pl.szczodrzynski.edziennik.ui.dialogs.base.BaseDialog class NotificationFilterDialog( activity: AppCompatActivity, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "NotificationFilterDialog" @@ -23,37 +24,24 @@ class NotificationFilterDialog( override fun getPositiveButtonText() = R.string.ok override fun getNegativeButtonText() = R.string.cancel - override fun getMultiChoiceItems(): Map { - notificationTypes = mapOf( - R.string.notification_type_timetable_lesson_change to Notification.TYPE_TIMETABLE_LESSON_CHANGE, - R.string.notification_type_new_grade to Notification.TYPE_NEW_GRADE, - R.string.notification_type_new_event to Notification.TYPE_NEW_EVENT, - R.string.notification_type_new_homework to Notification.TYPE_NEW_HOMEWORK, - R.string.notification_type_new_message to Notification.TYPE_NEW_MESSAGE, - R.string.notification_type_lucky_number to Notification.TYPE_LUCKY_NUMBER, - R.string.notification_type_notice to Notification.TYPE_NEW_NOTICE, - R.string.notification_type_attendance to Notification.TYPE_NEW_ATTENDANCE, - R.string.notification_type_new_announcement to Notification.TYPE_NEW_ANNOUNCEMENT, - R.string.notification_type_new_shared_event to Notification.TYPE_NEW_SHARED_EVENT, - R.string.notification_type_new_shared_homework to Notification.TYPE_NEW_SHARED_HOMEWORK, - R.string.notification_type_removed_shared_event to Notification.TYPE_REMOVED_SHARED_EVENT, - R.string.notification_type_new_teacher_absence to Notification.TYPE_TEACHER_ABSENCE, - ).mapKeys { (resId, _) -> activity.getString(resId) } - return notificationTypes - } + @Suppress("USELESS_CAST") + override fun getMultiChoiceItems() = NotificationType.values() + .filter { it.enabledByDefault != null } + .associateBy { it.titleRes.resolveString(activity) as CharSequence } - override fun getDefaultSelectedItems() = - notificationTypes.values.subtract(app.config.forProfile().sync.notificationFilter) + override fun getDefaultSelectedItems() = NotificationType.values() + .filter { it.enabledByDefault != null && it !in app.config.forProfile().sync.notificationFilter } + .toSet() override suspend fun onShow() = Unit - private lateinit var notificationTypes: Map - override suspend fun onPositiveClick(): Boolean { - val enabledTypes = getMultiSelection().filterIsInstance() - val disabledTypes = notificationTypes.values.subtract(enabledTypes).toList() + val enabledTypes = getMultiSelection() + val disabledTypes = NotificationType.values() + .filter { it.enabledByDefault != null && it !in enabledTypes } + .toSet() - if (disabledTypes.isNotEmpty()) { + if (disabledTypes.any { it.enabledByDefault == true }) { // warn user when he tries to disable some notifications MaterialAlertDialogBuilder(activity) .setTitle(R.string.are_you_sure) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/SyncIntervalDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/SyncIntervalDialog.kt index 433538a5..b64ce774 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/SyncIntervalDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/SyncIntervalDialog.kt @@ -16,7 +16,7 @@ class SyncIntervalDialog( private val onChangeListener: (() -> Unit)? = null, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "SyncIntervalDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt index 3a52dae5..34d86324 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/ThemeChooserDialog.kt @@ -13,7 +13,7 @@ class ThemeChooserDialog( activity: AppCompatActivity, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "ThemeChooserDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/ServerMessageDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/ServerMessageDialog.kt index 7ea7452e..b0f4f3fa 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/ServerMessageDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/ServerMessageDialog.kt @@ -14,7 +14,7 @@ class ServerMessageDialog( private val messageText: CharSequence, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "ServerMessageDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt index adc1a91a..55e185b7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt @@ -6,26 +6,21 @@ package pl.szczodrzynski.edziennik.ui.dialogs.sync import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask +import pl.szczodrzynski.edziennik.data.db.entity.Message +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.ext.resolveString +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.base.BaseDialog import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment class SyncViewListDialog( activity: MainActivity, - private val currentViewId: Int, + private val currentNavTarget: NavTarget, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "SyncViewListDialog" @@ -34,47 +29,25 @@ class SyncViewListDialog( override fun getNeutralButtonText() = R.string.sync_feature_all override fun getNegativeButtonText() = R.string.cancel - override fun getMultiChoiceItems(): Map { - items = mapOf( - R.string.menu_timetable to DRAWER_ITEM_TIMETABLE, - R.string.menu_agenda to DRAWER_ITEM_AGENDA, - R.string.menu_grades to DRAWER_ITEM_GRADES, - R.string.menu_homework to DRAWER_ITEM_HOMEWORK, - R.string.menu_notices to DRAWER_ITEM_BEHAVIOUR, - R.string.menu_attendance to DRAWER_ITEM_ATTENDANCE, - R.string.title_messages_inbox_single to (DRAWER_ITEM_MESSAGES to 0), - R.string.title_messages_sent_single to (DRAWER_ITEM_MESSAGES to 1), - R.string.menu_announcements to DRAWER_ITEM_ANNOUNCEMENTS, - ).mapKeys { (resId, _) -> activity.getString(resId) } - return items - } + @Suppress("USELESS_CAST") + override fun getMultiChoiceItems() = FeatureType.values() + .filter { it.nameRes != null } + .associateBy { it.nameRes!!.resolveString(activity) as CharSequence } - override fun getDefaultSelectedItems(): Set { - val everything = currentViewId == DRAWER_ITEM_HOME - return when { - everything -> items.values.toSet() - currentViewId == DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) { - 1 -> setOf(DRAWER_ITEM_MESSAGES to 1) - else -> setOf(DRAWER_ITEM_MESSAGES to 0) - } - else -> setOf(currentViewId) + override fun getDefaultSelectedItems() = when (currentNavTarget) { + NavTarget.HOME -> getMultiChoiceItems().values.toSet() + NavTarget.MESSAGES -> when (MessagesFragment.pageSelection) { + Message.TYPE_SENT -> setOf(FeatureType.MESSAGES_SENT) + else -> setOf(FeatureType.MESSAGES_INBOX) } + else -> currentNavTarget.featureType?.let { setOf(it) } ?: getMultiChoiceItems().values.toSet() } override suspend fun onShow() = Unit - private lateinit var items: Map - @Suppress("UNCHECKED_CAST") override suspend fun onPositiveClick(): Boolean { - val selected = getMultiSelection().mapNotNull { - when (it) { - is Int -> it to 0 - is Pair<*, *> -> it as Pair - else -> null - } - } - + val selected = getMultiSelection() if (selected.isEmpty()) return DISMISS diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/UpdateAvailableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/UpdateAvailableDialog.kt index c0335999..733febd8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/UpdateAvailableDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/UpdateAvailableDialog.kt @@ -20,7 +20,7 @@ class UpdateAvailableDialog( private val mandatory: Boolean = update?.updateMandatory ?: false, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "UpdateAvailableDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/error/ErrorDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/error/ErrorDetailsDialog.kt index b25cb2be..10822787 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/error/ErrorDetailsDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/error/ErrorDetailsDialog.kt @@ -21,7 +21,7 @@ class ErrorDetailsDialog( private val titleRes: Int = R.string.dialog_error_details_title, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "ErrorDetailsDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventDetailsDialog.kt index 6c906c27..efd8f700 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventDetailsDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventDetailsDialog.kt @@ -26,6 +26,7 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.databinding.DialogEventDetailsBinding import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog import pl.szczodrzynski.edziennik.ui.notes.setupNotesButton import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment @@ -195,7 +196,7 @@ class EventDetailsDialog( val dateStr = event.date.stringY_m_d val intent = - if (activity is MainActivity && activity.navTargetId == MainActivity.DRAWER_ITEM_TIMETABLE) + if (activity is MainActivity && activity.navTarget == NavTarget.TIMETABLE) Intent(TimetableFragment.ACTION_SCROLL_TO_DATE) else if (activity is MainActivity) Intent("android.intent.action.MAIN") @@ -203,8 +204,10 @@ class EventDetailsDialog( Intent(activity, MainActivity::class.java) intent.apply { - putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE) - putExtra("timetableDate", dateStr) + putExtras( + "fragmentId" to NavTarget.TIMETABLE, + "timetableDate" to dateStr, + ) } if (activity is MainActivity) activity.sendBroadcast(intent) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventManualDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventManualDialog.kt index 70526899..24b0aded 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventManualDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventManualDialog.kt @@ -24,6 +24,8 @@ import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.db.entity.* +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding @@ -170,9 +172,7 @@ class EventManualDialog( EdziennikTask.syncProfile( profileId = profileId, - viewIds = listOf( - MainActivity.DRAWER_ITEM_TIMETABLE to 0 - ), + featureTypes = setOf(FeatureType.TIMETABLE), arguments = JsonObject( "weekStart" to weekStart.stringY_m_d ) @@ -479,8 +479,8 @@ class EventManualDialog( val metadataObject = Metadata( profileId, when (type?.id) { - Event.TYPE_HOMEWORK -> Metadata.TYPE_HOMEWORK - else -> Metadata.TYPE_EVENT + Event.TYPE_HOMEWORK -> MetadataType.HOMEWORK + else -> MetadataType.EVENT }, eventObject.id, true, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt index 83ecb671..931a683d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt @@ -17,12 +17,12 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_GRADES_EDITOR import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.databinding.GradesListFragmentBinding import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog import pl.szczodrzynski.edziennik.ui.grades.models.GradesAverages import pl.szczodrzynski.edziennik.ui.grades.models.GradesSemester @@ -126,7 +126,7 @@ class GradesListFragment : Fragment(), CoroutineScope { gradeCountOtherSemester = otherSemester?.averages?.normalCount?.toFloat() } - activity.loadTarget(TARGET_GRADES_EDITOR, Bundle( + activity.navigate(navTarget = NavTarget.GRADES_EDITOR, args = Bundle( "subjectId" to subject.subjectId, "semester" to semester.number, "averageMode" to manager.yearAverageMode, @@ -152,7 +152,7 @@ class GradesListFragment : Fragment(), CoroutineScope { .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() - AsyncTask.execute { App.db.metadataDao().setAllSeen(App.profileId, TYPE_GRADE, true) } + AsyncTask.execute { App.db.metadataDao().setAllSeen(App.profileId, MetadataType.GRADE, true) } Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show() }) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeConfigDialog.kt index 73367c99..07b4229f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeConfigDialog.kt @@ -20,7 +20,7 @@ class HomeConfigDialog( private val reloadOnDismiss: Boolean = true, onShowListener: ((tag: String) -> Unit)? = null, onDismissListener: ((tag: String) -> Unit)? = null, -) : BaseDialog(activity, onShowListener, onDismissListener) { +) : BaseDialog(activity, onShowListener, onDismissListener) { override val TAG = "HomeConfigDialog" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt index 635c7b56..5a95c114 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt @@ -26,6 +26,7 @@ import pl.szczodrzynski.edziennik.BuildConfig import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ui.dialogs.settings.StudentNumberDialog @@ -125,7 +126,7 @@ class HomeFragment : Fragment(), CoroutineScope { .withOnClickListener(OnClickListener { activity.bottomSheet.close() launch { withContext(Dispatchers.Default) { - if (app.profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS) { + if (app.profile.loginStoreType != LoginType.LIBRUS) { app.db.metadataDao().setAllSeenExceptMessagesAndAnnouncements(App.profileId, true) } else { app.db.metadataDao().setAllSeenExceptMessages(App.profileId, true) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeArchiveCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeArchiveCard.kt index 73fc5610..2404d0f1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeArchiveCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeArchiveCard.kt @@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.ext.dp import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ext.setMessage import pl.szczodrzynski.edziennik.ext.setText +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.home.HomeCard import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter import pl.szczodrzynski.edziennik.ui.home.HomeFragment @@ -70,12 +71,12 @@ class HomeArchiveCard( .show() return@launch } - activity.loadProfile(profile) + activity.navigate(profile = profile) } } holder.root.onClick { - activity.loadTarget(MainActivity.DRAWER_ITEM_AGENDA) + activity.navigate(navTarget = NavTarget.AGENDA) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeEventsCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeEventsCard.kt index 96534719..db26d8e9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeEventsCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeEventsCard.kt @@ -22,6 +22,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.databinding.CardHomeEventsBinding import pl.szczodrzynski.edziennik.ext.dp import pl.szczodrzynski.edziennik.ext.onClick +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.event.EventDetailsDialog import pl.szczodrzynski.edziennik.ui.event.EventListAdapter import pl.szczodrzynski.edziennik.ui.event.EventManualDialog @@ -108,7 +109,7 @@ class HomeEventsCard( }) holder.root.onClick { - activity.loadTarget(MainActivity.DRAWER_ITEM_AGENDA) + activity.navigate(navTarget = NavTarget.AGENDA) } }} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeGradesCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeGradesCard.kt index c990b2b8..c64f2cc3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeGradesCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeGradesCard.kt @@ -30,6 +30,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Subject import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.databinding.CardHomeGradesBinding import pl.szczodrzynski.edziennik.ext.dp +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.grades.GradeView import pl.szczodrzynski.edziennik.ui.home.HomeCard import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter @@ -75,7 +76,7 @@ class HomeGradesCard( }) b.root.setOnClickListener { - activity.loadTarget(MainActivity.DRAWER_ITEM_GRADES) + activity.navigate(navTarget = NavTarget.GRADES) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeNotesCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeNotesCard.kt index f3758a2e..be829285 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeNotesCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeNotesCard.kt @@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.databinding.CardHomeNotesBinding import pl.szczodrzynski.edziennik.ext.dp import pl.szczodrzynski.edziennik.ext.onClick +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.home.HomeCard import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter import pl.szczodrzynski.edziennik.ui.home.HomeFragment @@ -114,7 +115,7 @@ class HomeNotesCard( b.addNote.onClick(this@HomeNotesCard::onNoteAddClick) holder.root.onClick { - activity.loadTarget(MainActivity.DRAWER_ITEM_NOTES) + activity.navigate(navTarget = NavTarget.NOTES) } }} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeTimetableCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeTimetableCard.kt index ab297ef8..965fc41b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeTimetableCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/cards/HomeTimetableCard.kt @@ -27,9 +27,11 @@ import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.CardHomeTimetableBinding import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.BellSyncTimeChooseDialog import pl.szczodrzynski.edziennik.ui.home.CounterActivity import pl.szczodrzynski.edziennik.ui.home.HomeCard @@ -120,9 +122,9 @@ class HomeTimetableCard( } b.root.onClick { - activity.loadTarget(MainActivity.DRAWER_ITEM_TIMETABLE, Bundle().apply { - putString("timetableDate", timetableDate.stringY_m_d) - }) + activity.navigate(navTarget = NavTarget.TIMETABLE, args = Bundle( + "timetableDate" to timetableDate.stringY_m_d, + )) } if (app.profile.getStudentData("timetableNotPublic", false)) { @@ -207,9 +209,7 @@ class HomeTimetableCard( it.isEnabled = false EdziennikTask.syncProfile( profileId = profile.id, - viewIds = listOf( - MainActivity.DRAWER_ITEM_TIMETABLE to 0 - ), + featureTypes = setOf(FeatureType.TIMETABLE), arguments = JsonObject( "weekStart" to weekStart.stringY_m_d ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/homework/HomeworkFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/homework/HomeworkFragment.kt index d041d298..f47fa63e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/homework/HomeworkFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/homework/HomeworkFragment.kt @@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.databinding.HomeworkFragmentBinding import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.addOnPageSelectedListener @@ -73,7 +74,7 @@ class HomeworkFragment : Fragment(), CoroutineScope { .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() - AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, Metadata.TYPE_HOMEWORK, true) } + AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, MetadataType.HOMEWORK, true) } Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show() })) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt index a4367dee..f48258a9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginChooserFragment.kt @@ -25,6 +25,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog @@ -81,18 +83,17 @@ class LoginChooserFragment : Fragment(), CoroutineScope { app.buildManager.showVersionDialog(activity) if (!App.devMode) return@onClick - if (adapter.items.firstOrNull { it is LoginInfo.Register && it.internalName == "lab" } != null) + if (adapter.items.firstOrNull { it is LoginInfo.Register && it.loginType == LoginType.TEMPLATE } != null) return@onClick adapter.items.add( index = 0, element = LoginInfo.Register( - loginType = 999999, - internalName = "lab", + loginType = LoginType.TEMPLATE, registerName = R.string.menu_lab, registerLogo = R.drawable.face_2, loginModes = listOf( LoginInfo.Mode( - loginMode = 0, + loginMode = LoginMode.PODLASIE_API, name = 0, icon = 0, guideText = 0, @@ -196,13 +197,12 @@ class LoginChooserFragment : Fragment(), CoroutineScope { adapter.items.removeAll { it !is LoginInfo.Register } adapter.items.add( LoginInfo.Register( - loginType = 74, - internalName = "eggs", + loginType = LoginType.DEMO, registerName = R.string.eggs, registerLogo = R.drawable.face_1, loginModes = listOf( LoginInfo.Mode( - loginMode = 0, + loginMode = LoginMode.PODLASIE_API, name = 0, icon = 0, guideText = 0, @@ -241,12 +241,12 @@ class LoginChooserFragment : Fragment(), CoroutineScope { loginType: LoginInfo.Register, loginMode: LoginInfo.Mode ) { - if (loginType.internalName == "eggs") { + if (loginType.loginType == LoginType.DEMO) { nav.navigate(R.id.loginEggsFragment, null, activity.navOptions) return } - if (loginType.internalName == "lab") { + if (loginType.loginType == LoginType.TEMPLATE) { nav.navigate(R.id.labFragment, null, activity.navOptions) return } @@ -303,7 +303,7 @@ class LoginChooserFragment : Fragment(), CoroutineScope { ), activity.navOptions) } - private suspend fun checkAvailability(loginType: Int): Boolean { + private suspend fun checkAvailability(loginType: LoginType): Boolean { val error = withContext(Dispatchers.IO) { app.availabilityManager.check(loginType) } ?: return true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFinishFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFinishFragment.kt index e7703dab..ee9e34af 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFinishFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFinishFragment.kt @@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.databinding.LoginFinishFragmentBinding import pl.szczodrzynski.edziennik.ext.Intent import pl.szczodrzynski.edziennik.ext.onClick +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import kotlin.coroutines.CoroutineContext class LoginFinishFragment : Fragment(), CoroutineScope { @@ -64,14 +65,14 @@ class LoginFinishFragment : Fragment(), CoroutineScope { activity, MainActivity::class.java, "profileId" to firstProfileId, - "fragmentId" to MainActivity.DRAWER_ITEM_HOME + "fragmentId" to NavTarget.HOME )) } else { activity.setResult(Activity.RESULT_OK, Intent( null, "profileId" to firstProfileId, - "fragmentId" to MainActivity.DRAWER_ITEM_HOME + "fragmentId" to NavTarget.HOME )) } activity.finish() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt index 12daadcd..c4485aba 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginFormFragment.kt @@ -26,6 +26,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.LoginFormCheckboxItemBinding import pl.szczodrzynski.edziennik.databinding.LoginFormFieldItemBinding import pl.szczodrzynski.edziennik.databinding.LoginFormFragmentBinding @@ -88,9 +90,9 @@ class LoginFormFragment : Fragment(), CoroutineScope { b.errorLayout.isVisible = false b.errorLayout.background?.setTintColor(R.attr.colorError.resolveAttr(activity)) - val loginType = arguments?.getInt("loginType") ?: return + val loginType = arguments?.getEnum("loginType") ?: return val register = LoginInfo.list.firstOrNull { it.loginType == loginType } ?: return - val loginMode = arguments?.getInt("loginMode") ?: return + val loginMode = arguments?.getEnum("loginMode") ?: return val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return if (mode.credentials.isEmpty()) { @@ -103,7 +105,7 @@ class LoginFormFragment : Fragment(), CoroutineScope { b.text.text = platformGuideText ?: app.getString(mode.guideText) // eggs - isEggs = register.internalName == "podlasie" + isEggs = register.loginType == LoginType.PODLASIE for (credential in mode.credentials) { if (platformFormFields?.contains(credential.keyName) == false) @@ -248,7 +250,7 @@ class LoginFormFragment : Fragment(), CoroutineScope { } } - private fun login(loginType: Int, loginMode: Int) { + private fun login(loginType: LoginType, loginMode: LoginMode) { val payload = Bundle( "loginType" to loginType, "loginMode" to loginMode diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt index 774530f1..33e191d7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginInfo.kt @@ -11,6 +11,8 @@ import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.* +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ui.grades.models.ExpandableItemModel import pl.szczodrzynski.edziennik.ui.login.qr.LoginLibrusQrDecoder import pl.szczodrzynski.edziennik.ui.login.qr.LoginQrDecoder @@ -46,13 +48,12 @@ object LoginInfo { val list by lazy { listOf( Register( - loginType = LOGIN_TYPE_LIBRUS, - internalName = "librus", + loginType = LoginType.LIBRUS, registerName = R.string.login_register_librus, registerLogo = R.drawable.login_logo_librus, loginModes = listOf( Mode( - loginMode = LOGIN_MODE_LIBRUS_EMAIL, + loginMode = LoginMode.LIBRUS_EMAIL, name = R.string.login_mode_librus_email, icon = R.drawable.login_mode_librus_email, hintText = R.string.login_mode_librus_email_hint, @@ -68,7 +69,7 @@ object LoginInfo { ) ), /*Mode( - loginMode = LOGIN_MODE_LIBRUS_SYNERGIA, + loginMode = LoginMode.LIBRUS_SYNERGIA, name = R.string.login_mode_librus_synergia, icon = R.drawable.login_mode_librus_synergia, hintText = R.string.login_mode_librus_synergia_hint, @@ -93,7 +94,7 @@ object LoginInfo { ) ),*/ Mode( - loginMode = LOGIN_MODE_LIBRUS_JST, + loginMode = LoginMode.LIBRUS_JST, name = R.string.login_mode_librus_jst, icon = R.drawable.login_mode_librus_jst, hintText = R.string.login_mode_librus_jst_hint, @@ -131,13 +132,12 @@ object LoginInfo { ) ), Register( - loginType = LOGIN_TYPE_VULCAN, - internalName = "vulcan", + loginType = LoginType.VULCAN, registerName = R.string.login_type_vulcan, registerLogo = R.drawable.login_logo_vulcan, loginModes = listOf( Mode( - loginMode = LOGIN_MODE_VULCAN_HEBE, + loginMode = LoginMode.VULCAN_HEBE, name = R.string.login_mode_vulcan_api, icon = R.drawable.login_mode_vulcan_hebe, hintText = R.string.login_mode_vulcan_api_hint, @@ -192,7 +192,7 @@ object LoginInfo { errorCodes = mapOf() ), Mode( - loginMode = LOGIN_MODE_VULCAN_WEB, + loginMode = LoginMode.VULCAN_WEB, name = R.string.login_mode_vulcan_web, icon = R.drawable.login_mode_vulcan_web, hintText = R.string.login_mode_vulcan_web_hint, @@ -219,13 +219,12 @@ object LoginInfo { ) ), Register( - loginType = LOGIN_TYPE_MOBIDZIENNIK, - internalName = "mobidziennik", + loginType = LoginType.MOBIDZIENNIK, registerName = R.string.login_type_mobidziennik, registerLogo = R.drawable.login_logo_mobidziennik, loginModes = listOf( Mode( - loginMode = LOGIN_MODE_MOBIDZIENNIK_WEB, + loginMode = LoginMode.MOBIDZIENNIK_WEB, name = R.string.login_mode_mobidziennik_web, icon = R.drawable.login_mode_mobidziennik_web, hintText = R.string.login_mode_mobidziennik_web_hint, @@ -279,13 +278,12 @@ object LoginInfo { ) ), Register( - loginType = LOGIN_TYPE_PODLASIE, - internalName = "podlasie", + loginType = LoginType.PODLASIE, registerName = R.string.login_type_podlasie, registerLogo = R.drawable.login_logo_podlasie, loginModes = listOf( Mode( - loginMode = LOGIN_MODE_PODLASIE_API, + loginMode = LoginMode.PODLASIE_API, name = R.string.login_mode_podlasie_api, icon = R.drawable.login_mode_podlasie_api, guideText = R.string.login_mode_podlasie_api_guide, @@ -315,13 +313,12 @@ object LoginInfo { ) ), Register( - loginType = LOGIN_TYPE_USOS, - internalName = "usos", + loginType = LoginType.USOS, registerName = R.string.login_type_usos, registerLogo = R.drawable.login_logo_usos, loginModes = listOf( Mode( - loginMode = LOGIN_MODE_USOS_OAUTH, + loginMode = LoginMode.USOS_OAUTH, name = R.string.login_mode_usos_oauth, icon = R.drawable.login_mode_usos_api, guideText = R.string.login_mode_usos_oauth_guide, @@ -335,8 +332,7 @@ object LoginInfo { } data class Register( - val loginType: Int, - val internalName: String, + val loginType: LoginType, val registerName: Int, @DrawableRes val registerLogo: Int, @@ -347,7 +343,7 @@ object LoginInfo { } data class Mode( - val loginMode: Int, + val loginMode: LoginMode, @StringRes val name: Int, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt index 5629487f..5055e228 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginPlatformListFragment.kt @@ -17,8 +17,11 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.LoginPlatformListFragmentBinding import pl.szczodrzynski.edziennik.ext.Bundle +import pl.szczodrzynski.edziennik.ext.getEnum import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ext.startCoroutineTimer import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration @@ -56,9 +59,9 @@ class LoginPlatformListFragment : Fragment(), CoroutineScope { if (!isAdded) return b.backButton.onClick { nav.navigateUp() } - val loginType = arguments?.getInt("loginType") ?: return + val loginType = arguments?.getEnum("loginType") ?: return val register = LoginInfo.list.firstOrNull { it.loginType == loginType } ?: return - val loginMode = arguments?.getInt("loginMode") ?: return + val loginMode = arguments?.getEnum("loginMode") ?: return val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return adapter = LoginPlatformAdapter(activity) { platform -> @@ -100,7 +103,7 @@ class LoginPlatformListFragment : Fragment(), CoroutineScope { val platforms = LoginInfo.platformList[mode.name] ?: run { api.runCatching(activity) { - getRealms(register.internalName) + getRealms(register.loginType.name.lowercase()) } ?: run { nav.navigateUp() return@launch diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt index 87a01008..a0ad6e78 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginProgressFragment.kt @@ -27,7 +27,10 @@ import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.enums.LoginMode +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding +import pl.szczodrzynski.edziennik.ext.getEnum import pl.szczodrzynski.edziennik.ext.joinNotNullStrings import pl.szczodrzynski.edziennik.utils.managers.UserActionManager import kotlin.coroutines.CoroutineContext @@ -79,8 +82,8 @@ class LoginProgressFragment : Fragment(), CoroutineScope { app.db.profileDao().lastId ?: 0, activity.profiles.maxByOrNull { it.profile.id }?.profile?.id ?: 0 ) - val loginType = args.getInt("loginType", -1) - val loginMode = args.getInt("loginMode", 0) + val loginType = args.getEnum("loginType") ?: return@launch + val loginMode = args.getEnum("loginMode") ?: return@launch val loginStore = LoginStore( id = maxProfileId + 1, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginSyncFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginSyncFragment.kt index 64384bbc..6d3068b8 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginSyncFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/login/LoginSyncFragment.kt @@ -81,7 +81,7 @@ class LoginSyncFragment : Fragment(), CoroutineScope { "firstProfileId" to profiles.firstOrNull()?.id ) - val profileIds = profiles.map { it.id } + val profileIds = profiles.map { it.id }.toSet() EdziennikTask.syncProfileList(profileIds).enqueue(activity) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeFragment.kt index 52e7c23b..768c395e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/compose/MessagesComposeFragment.kt @@ -25,9 +25,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES import pl.szczodrzynski.edziennik.data.api.ERROR_MESSAGE_NOT_SENT -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent @@ -35,9 +33,11 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.DAY +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.settings.MessagesConfigDialog import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment import pl.szczodrzynski.edziennik.utils.DefaultTextStyles @@ -77,7 +77,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { private lateinit var stylingConfig: StylingConfig private lateinit var uiConfig: UIConfig private val enableTextStyling - get() = app.profile.loginStoreType != LoginStore.LOGIN_TYPE_LIBRUS + get() = app.profile.loginStoreType != LoginType.LIBRUS private var changedRecipients = false private var changedSubject = false private var changedBody = false @@ -161,7 +161,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { } private fun getRecipientList() { - if (System.currentTimeMillis() - app.profile.lastReceiversSync > 1 * DAY * 1000 && app.profile.loginStoreType != LoginStore.LOGIN_TYPE_VULCAN) { + if (System.currentTimeMillis() - app.profile.lastReceiversSync > 1 * DAY * 1000 && app.profile.loginStoreType != LoginType.VULCAN) { activity.snackbar("Pobieranie listy odbiorców...") EdziennikTask.recipientListGet(App.profileId).enqueue(activity) } @@ -194,19 +194,19 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { }) b.subjectLayout.counterMaxLength = when (app.profile.loginStoreType) { - LoginStore.LOGIN_TYPE_MOBIDZIENNIK -> 100 - LoginStore.LOGIN_TYPE_LIBRUS -> 150 - LoginStore.LOGIN_TYPE_VULCAN -> 200 - LoginStore.LOGIN_TYPE_IDZIENNIK -> 180 - LoginStore.LOGIN_TYPE_EDUDZIENNIK -> 0 + LoginType.MOBIDZIENNIK -> 100 + LoginType.LIBRUS -> 150 + LoginType.VULCAN -> 200 + LoginType.IDZIENNIK -> 180 + LoginType.EDUDZIENNIK -> 0 else -> -1 } b.textLayout.counterMaxLength = when (app.profile.loginStoreType) { - LoginStore.LOGIN_TYPE_MOBIDZIENNIK -> -1 - LoginStore.LOGIN_TYPE_LIBRUS -> 20000 - LoginStore.LOGIN_TYPE_VULCAN -> -1 - LoginStore.LOGIN_TYPE_IDZIENNIK -> 1983 - LoginStore.LOGIN_TYPE_EDUDZIENNIK -> 0 + LoginType.MOBIDZIENNIK -> -1 + LoginType.LIBRUS -> 20000 + LoginType.VULCAN -> -1 + LoginType.IDZIENNIK -> 1983 + LoginType.EDUDZIENNIK -> 0 else -> -1 } @@ -257,7 +257,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { styles = styles, textHtml = if (App.devMode) b.textHtml else null, htmlMode = when (app.profile.loginStoreType) { - LOGIN_TYPE_MOBIDZIENNIK -> COMPATIBLE + LoginType.MOBIDZIENNIK -> COMPATIBLE else -> ORIGINAL }, ) @@ -303,7 +303,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { .setPositiveButton(R.string.save) { _, _ -> saveDraft() MessagesFragment.pageSelection = Message.TYPE_DRAFT - activity.loadTarget(DRAWER_ITEM_MESSAGES, skipBeforeNavigate = true) + activity.navigate(navTarget = NavTarget.MESSAGES, skipBeforeNavigate = true) } .setNegativeButton(R.string.discard) { _, _ -> activity.resumePausedNavigation() @@ -393,7 +393,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { b.recipientsLayout.error = getString(R.string.messages_compose_recipients_error) return } - val recipients = mutableListOf() + val recipients = mutableSetOf() b.recipients.allChips.forEach { chip -> if (chip.data !is Teacher) return@forEach @@ -487,7 +487,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope { } activity.snackbar(app.getString(R.string.messages_sent_success), app.getString(R.string.ok)) - activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, Bundle( + activity.navigate(navTarget = NavTarget.MESSAGE, args = Bundle( "messageId" to event.message.id, "message" to app.gson.toJson(event.message), "sentDate" to event.sentDate diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesFragment.kt index 92cab017..823a3289 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesFragment.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.databinding.MessagesFragmentBinding import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.addOnPageSelectedListener +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.base.lazypager.FragmentLazyPagerAdapter import pl.szczodrzynski.edziennik.ui.dialogs.settings.MessagesConfigDialog import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem @@ -52,7 +53,7 @@ class MessagesFragment : Fragment(), CoroutineScope { val args = Bundle() args.putLong("messageId", messageId) arguments?.remove("messageId") - activity.loadTarget(MainActivity.TARGET_MESSAGES_DETAILS, args) + activity.navigate(navTarget = NavTarget.MESSAGE, args = args) return } @@ -123,7 +124,7 @@ class MessagesFragment : Fragment(), CoroutineScope { ) setFabOnClickListener { - activity.loadTarget(MainActivity.TARGET_MESSAGES_COMPOSE) + activity.navigate(navTarget = NavTarget.MESSAGE_COMPOSE) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesListFragment.kt index fb6edc56..fc19abfa 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/list/MessagesListFragment.kt @@ -13,14 +13,13 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.* -import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_MESSAGES_COMPOSE -import pl.szczodrzynski.edziennik.MainActivity.Companion.TARGET_MESSAGES_DETAILS import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.databinding.MessagesListFragmentBinding import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.startCoroutineTimer +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration import kotlin.coroutines.CoroutineContext @@ -65,11 +64,11 @@ class MessagesListFragment : LazyFragment(), CoroutineScope { adapter = MessagesAdapter(activity, teachers, onMessageClick = { val (target, args) = if (it.isDraft) { - TARGET_MESSAGES_COMPOSE to Bundle("message" to app.gson.toJson(it)) + NavTarget.MESSAGE_COMPOSE to Bundle("message" to app.gson.toJson(it)) } else { - TARGET_MESSAGES_DETAILS to Bundle("messageId" to it.id) + NavTarget.MESSAGE to Bundle("messageId" to it.id) } - activity.loadTarget(target, args) + activity.navigate(navTarget = target, args = args) }, onStarClick = { this@MessagesListFragment.launch { manager.starMessage(it, !it.isStarred) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/single/MessageFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/single/MessageFragment.kt index 27c90f4f..4a68ad95 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/single/MessageFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/messages/single/MessageFragment.kt @@ -22,11 +22,11 @@ import org.greenrobot.eventbus.ThreadMode import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore.Companion.LOGIN_TYPE_IDZIENNIK +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.databinding.MessageFragmentBinding import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.settings.MessagesConfigDialog import pl.szczodrzynski.edziennik.ui.messages.MessagesUtils import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment @@ -125,13 +125,13 @@ class MessageFragment : Fragment(), CoroutineScope { b.messageStar.attachToastHint(R.string.hint_message_star) b.replyButton.onClick { - activity.loadTarget(MainActivity.TARGET_MESSAGES_COMPOSE, Bundle( + activity.navigate(navTarget = NavTarget.MESSAGE_COMPOSE, args = Bundle( "message" to app.gson.toJson(message), "type" to "reply" )) } b.forwardButton.onClick { - activity.loadTarget(MainActivity.TARGET_MESSAGES_COMPOSE, Bundle( + activity.navigate(navTarget = NavTarget.MESSAGE_COMPOSE, args = Bundle( "message" to app.gson.toJson(message), "type" to "forward" )) @@ -178,7 +178,7 @@ class MessageFragment : Fragment(), CoroutineScope { return } - if (app.profile.loginStoreType == LOGIN_TYPE_IDZIENNIK) { + if (app.profile.loginStoreType == LoginType.IDZIENNIK) { val meta = "\\[META:([A-z0-9]+);([0-9-]+)]".toRegex().find(message.body!!) val messageIdBefore = meta?.get(2)?.toLong() ?: -1 @@ -188,7 +188,7 @@ class MessageFragment : Fragment(), CoroutineScope { } } - if (app.profile.loginStoreType == LoginStore.LOGIN_TYPE_VULCAN) { + if (app.profile.loginStoreType == LoginType.VULCAN) { // vulcan: change message status or download attachments if ((message.isReceived || message.isDeleted) && !message.seen || message.attachmentIds == null) { EdziennikTask.messageGet(App.profileId, message).enqueue(activity) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsAdapter.kt index dfecbfcf..ee2d8746 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsAdapter.kt @@ -47,7 +47,7 @@ class NotificationsAdapter( val date = Date.fromMillis(item.addedDate).formattedString val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) - b.notificationIcon.background = IconicsDrawable(app, item.getLargeIcon()).apply { + b.notificationIcon.background = IconicsDrawable(app, item.type.icon).apply { colorRes = R.color.colorPrimary } @@ -57,7 +57,7 @@ class NotificationsAdapter( " • ", date ).concat().asColoredSpannable(colorSecondary) - b.type.text = activity.getNotificationTitle(item.type) + b.type.text = item.type.titleRes.resolveString(activity) onItemClick?.let { listener -> b.root.onClick { listener(item) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsListFragment.kt index 95a1bd70..f2a98f11 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/notifications/NotificationsListFragment.kt @@ -67,14 +67,14 @@ class NotificationsListFragment : Fragment(), CoroutineScope { val intent = Intent("android.intent.action.MAIN") notification.fillIntent(intent) - Utils.d(TAG, "notification with item " + notification.viewId + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString()) + Utils.d(TAG, "notification with item " + notification.navTarget + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString()) if (notification.profileId != null && notification.profileId != -1 && notification.profileId != app.profile.id && context is Activity) { Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show() } app.sendBroadcast(intent) } - app.db.notificationDao().getAll().observe(this@NotificationsListFragment, Observer { items -> + app.db.notificationDao().getAll().observe(viewLifecycleOwner, Observer { items -> if (!isAdded) return@Observer // load & configure the adapter diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt index 0d574419..fc369b6a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt @@ -9,7 +9,7 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria import eu.szkolny.font.SzkolnyFont import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_LIBRUS +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.after import pl.szczodrzynski.edziennik.ui.dialogs.settings.* import pl.szczodrzynski.edziennik.ui.settings.SettingsCard @@ -150,7 +150,7 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { configGlobal.timetable.countInSeconds = it }, - if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS) + if (app.profile.loginStoreType == LoginType.LIBRUS) util.createPropertyItem( text = R.string.settings_register_show_teacher_absences_text, icon = CommunityMaterial.Icon.cmd_account_arrow_right_outline, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsSyncCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsSyncCard.kt index 13384e75..ba1c0981 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsSyncCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsSyncCard.kt @@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.ext.after import pl.szczodrzynski.edziennik.ext.getSyncInterval import pl.szczodrzynski.edziennik.sync.SyncWorker import pl.szczodrzynski.edziennik.sync.UpdateWorker +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.settings.NotificationFilterDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.QuietHoursConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.SyncIntervalDialog @@ -151,7 +152,7 @@ class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) { subText = R.string.settings_sync_web_push_subtext, icon = CommunityMaterial.Icon2.cmd_laptop ) { - activity.loadTarget(MainActivity.TARGET_WEB_PUSH) + activity.navigate(navTarget = NavTarget.WEB_PUSH) } ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt index 2edfa8cc..28a6541c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/teachers/TeachersAdapter.kt @@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Subject import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.databinding.TeacherItemBinding import pl.szczodrzynski.edziennik.ext.* +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import kotlin.coroutines.CoroutineContext class TeachersAdapter( @@ -67,7 +68,7 @@ class TeachersAdapter( b.sendMessage.onClick { val intent = Intent( Intent.ACTION_MAIN, - "fragmentId" to MainActivity.TARGET_MESSAGES_COMPOSE, + "fragmentId" to NavTarget.MESSAGE_COMPOSE, "messageRecipientId" to item.id ) activity.sendBroadcast(intent) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/template/TemplateAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/template/TemplateAdapter.kt index 7ff8b162..9e5300cb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/template/TemplateAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/template/TemplateAdapter.kt @@ -54,7 +54,7 @@ class TemplateAdapter( " • ", date ).concat().asColoredSpannable(colorSecondary) - b.type.text = activity.getNotificationTitle(item.type) + b.type.text = item.type.titleRes.resolveString(app) onItemClick?.let { listener -> b.root.onClick { listener(item) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/GenerateBlockTimetableDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/GenerateBlockTimetableDialog.kt index aaf98941..701ed9ed 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/GenerateBlockTimetableDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/GenerateBlockTimetableDialog.kt @@ -31,6 +31,7 @@ import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent import pl.szczodrzynski.edziennik.data.db.entity.Lesson +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogGenerateBlockTimetableBinding import pl.szczodrzynski.edziennik.ext.* @@ -202,9 +203,7 @@ class GenerateBlockTimetableDialog( EdziennikTask.syncProfile( profileId = App.profileId, - viewIds = listOf( - MainActivity.DRAWER_ITEM_TIMETABLE to 0 - ), + featureTypes = setOf(FeatureType.TIMETABLE), arguments = JsonObject( "weekStart" to weekStart.stringY_m_d ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt index b901cdfc..4a03a099 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableDayFragment.kt @@ -21,13 +21,11 @@ import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp import kotlinx.coroutines.* -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.MainActivity -import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS +import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.db.entity.Lesson +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull @@ -85,7 +83,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { startHour = startHour, endHour = endHour, dividerHeight = 1.dp, - halfHourHeight = if (app.profile.loginStoreType == LOGIN_TYPE_USOS) 45.dp else 60.dp, + halfHourHeight = if (app.profile.loginStoreType == LoginType.USOS) 45.dp else 60.dp, hourDividerColor = R.attr.hourDividerColor.resolveAttr(context), halfHourDividerColor = R.attr.halfHourDividerColor.resolveAttr(context), hourLabelWidth = 40.dp, @@ -146,9 +144,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope { it.isEnabled = false EdziennikTask.syncProfile( profileId = App.profileId, - viewIds = listOf( - DRAWER_ITEM_TIMETABLE to 0 - ), + featureTypes = setOf(FeatureType.TIMETABLE), arguments = JsonObject( "weekStart" to weekStart ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt index fc2221bc..196aeee9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/timetable/TimetableFragment.kt @@ -24,6 +24,7 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Metadata +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains import pl.szczodrzynski.edziennik.ui.dialogs.settings.TimetableConfigDialog @@ -223,7 +224,7 @@ class TimetableFragment : Fragment(), CoroutineScope { .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) .withOnClickListener(View.OnClickListener { activity.bottomSheet.close() - AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, Metadata.TYPE_LESSON_CHANGE, true) } + AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, MetadataType.LESSON_CHANGE, true) } Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show() }) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/LessonDialogActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/LessonDialogActivity.kt index 32ee7d82..609657b5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/LessonDialogActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/LessonDialogActivity.kt @@ -13,6 +13,8 @@ import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.* import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.ext.Intent +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.timetable.LessonDetailsDialog import pl.szczodrzynski.edziennik.utils.Themes import kotlin.coroutines.CoroutineContext @@ -44,11 +46,12 @@ class LessonDialogActivity : AppCompatActivity(), CoroutineScope { val profileId = extras?.getInt("profileId") ?: return@async null if (extras.getBoolean("separatorItem", false)) { - val i = Intent(app, MainActivity::class.java) - .putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE) - .putExtra("profileId", profileId) - .putExtra("timetableDate", extras.getString("timetableDate", null)) - .addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT or FLAG_ACTIVITY_NEW_TASK) + val i = Intent( + app, MainActivity::class.java, + "fragmentId" to NavTarget.TIMETABLE, + "profileId" to profileId, + "timetableDate" to extras.getString("timetableDate", null), + ).addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT or FLAG_ACTIVITY_NEW_TASK) app.startActivity(i) finish() return@async null diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java index 028bb482..b5d204f4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/WidgetConfigActivity.java @@ -29,6 +29,7 @@ import java.util.List; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.data.db.entity.Profile; +import pl.szczodrzynski.edziennik.data.db.enums.LoginType; import pl.szczodrzynski.edziennik.databinding.DialogWidgetConfigBinding; import pl.szczodrzynski.edziennik.databinding.WidgetProfileDialogItemBinding; import pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider; @@ -102,7 +103,7 @@ public class WidgetConfigActivity extends Activity { profileList.add( new Profile(-1, 0, - 0, + LoginType.TEMPLATE, getString(R.string.widget_config_all_profiles), null, "", diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/luckynumber/WidgetLuckyNumberProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/luckynumber/WidgetLuckyNumberProvider.kt index 40b40d5c..bde01d34 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/luckynumber/WidgetLuckyNumberProvider.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/luckynumber/WidgetLuckyNumberProvider.kt @@ -17,6 +17,8 @@ import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.ext.getJsonObject import pl.szczodrzynski.edziennik.ext.pendingIntentFlag +import pl.szczodrzynski.edziennik.ext.putExtras +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.models.Date @@ -81,7 +83,7 @@ class WidgetLuckyNumberProvider : AppWidgetProvider() { val openIntent = Intent(context, MainActivity::class.java) openIntent.action = Intent.ACTION_MAIN - openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_HOME) + openIntent.putExtras("fragmentId" to NavTarget.HOME) val openPendingIntent = PendingIntent.getActivity(context, 0, openIntent, pendingIntentFlag()) views.setOnClickPendingIntent(R.id.widgetLuckyNumberRoot, openPendingIntent) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsFactory.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsFactory.kt index 587837a8..11825724 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsFactory.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsFactory.kt @@ -14,10 +14,8 @@ import com.google.gson.JsonParser import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Notification -import pl.szczodrzynski.edziennik.ext.getInt -import pl.szczodrzynski.edziennik.ext.getLong -import pl.szczodrzynski.edziennik.ext.getNotificationTitle -import pl.szczodrzynski.edziennik.ext.getString +import pl.szczodrzynski.edziennik.data.db.enums.NotificationType +import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig import pl.szczodrzynski.edziennik.utils.models.Date @@ -51,11 +49,11 @@ class WidgetNotificationsFactory(val app: App, val config: WidgetConfig) : Remot getString("title") ?: "", getString("text") ?: "", getString("textLong"), - getInt("type") ?: 0, + getInt("type")?.asNotificationTypeOrNull() ?: NotificationType.GENERAL, getInt("profileId"), getString("profileName"), getInt("posted") == 1, - getInt("viewId"), + getInt("viewId")?.asNavTargetOrNull(), getString("extras")?.let { JsonParser.parseString(it).asJsonObject }, getLong("addedDate") ?: System.currentTimeMillis() ) @@ -63,7 +61,7 @@ class WidgetNotificationsFactory(val app: App, val config: WidgetConfig) : Remot views.apply { setTextViewText(R.id.widgetNotificationsTitle, - app.getString(R.string.widget_notifications_title_format, notification.title, app.getNotificationTitle(notification.type))) + app.getString(R.string.widget_notifications_title_format, notification.title, notification.type.titleRes.resolveString(app))) setTextViewText(R.id.widgetNotificationsText, notification.text) setTextViewText(R.id.widgetNotificationsDate, Date.fromMillis(notification.addedDate).formattedString) setOnClickFillInIntent(R.id.widgetNotificationsRoot, Intent().also { notification.fillIntent(it) }) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt index dc4eb02e..b4af3f68 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/notifications/WidgetNotificationsProvider.kt @@ -23,7 +23,9 @@ import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.getJsonObject import pl.szczodrzynski.edziennik.ext.pendingIntentFlag +import pl.szczodrzynski.edziennik.ext.putExtras import pl.szczodrzynski.edziennik.receivers.SzkolnyReceiver +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig class WidgetNotificationsProvider : AppWidgetProvider() { @@ -74,7 +76,7 @@ class WidgetNotificationsProvider : AppWidgetProvider() { val headerIntent = Intent(context, MainActivity::class.java) headerIntent.action = Intent.ACTION_MAIN - headerIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS) + headerIntent.putExtras("fragmentId" to NavTarget.NOTIFICATIONS) val headerPendingIntent = PendingIntent.getActivity(context, 0, headerIntent, pendingIntentFlag()) views.setOnClickPendingIntent(R.id.widgetNotificationsHeader, headerPendingIntent) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt index 60eeb6cc..7fc82875 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/widgets/timetable/WidgetTimetableProvider.kt @@ -32,6 +32,8 @@ import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_NO_LESSON import pl.szczodrzynski.edziennik.ext.filterOutArchived import pl.szczodrzynski.edziennik.ext.getJsonObject import pl.szczodrzynski.edziennik.ext.pendingIntentFlag +import pl.szczodrzynski.edziennik.ext.putExtras +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.widgets.LessonDialogActivity import pl.szczodrzynski.edziennik.ui.widgets.WidgetConfig import pl.szczodrzynski.edziennik.utils.models.Date @@ -394,7 +396,7 @@ class WidgetTimetableProvider : AppWidgetProvider() { headerIntent.putExtra("timetableDate", it.value) } } - headerIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE) + headerIntent.putExtras("fragmentId" to NavTarget.TIMETABLE) val headerPendingIntent = PendingIntent.getActivity(app, appWidgetId, headerIntent, pendingIntentFlag()) views.setOnClickPendingIntent(R.id.widgetTimetableHeader, headerPendingIntent) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt index 0665704d..f0cc9c13 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt @@ -28,6 +28,7 @@ import pl.szczodrzynski.edziennik.ext.Intent import pl.szczodrzynski.edziennik.ext.copyToClipboard import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.getTextPosition +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.models.Date @SuppressLint("RestrictedApi") @@ -116,7 +117,7 @@ object BetterLink { ).setOnMenuItemClickListener { val intent = Intent( Intent.ACTION_MAIN, - "fragmentId" to MainActivity.TARGET_MESSAGES_COMPOSE, + "fragmentId" to NavTarget.MESSAGE_COMPOSE, "messageRecipientId" to teacherId ) context.sendBroadcast(intent) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/PausedNavigationData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/PausedNavigationData.kt index 83d7ae96..b5975089 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/PausedNavigationData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/PausedNavigationData.kt @@ -5,17 +5,10 @@ package pl.szczodrzynski.edziennik.utils import android.os.Bundle +import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget -open class PausedNavigationData { - - data class LoadProfile( - val id: Int, - val drawerSelection: Int, - val arguments: Bundle?, - ) : PausedNavigationData() - - data class LoadTarget( - val id: Int, - val arguments: Bundle?, - ) : PausedNavigationData() -} +data class PausedNavigationData( + val profileId: Int?, + val navTarget: NavTarget?, + val args: Bundle?, +) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AvailabilityManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AvailabilityManager.kt index 83d579d8..2c989a5a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AvailabilityManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/AvailabilityManager.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.toApiError @@ -48,17 +49,8 @@ class AvailabilityManager(val app: App) { return check(profile.registerName, cacheOnly) } - fun check(loginType: Int, cacheOnly: Boolean = false): Error? { - val registerName = when (loginType) { - LOGIN_TYPE_LIBRUS -> "librus" - LOGIN_TYPE_VULCAN -> "vulcan" - LOGIN_TYPE_IDZIENNIK -> "idziennik" - LOGIN_TYPE_MOBIDZIENNIK -> "mobidziennik" - LOGIN_TYPE_PODLASIE -> "podlasie" - LOGIN_TYPE_EDUDZIENNIK -> "edudziennik" - else -> "unknown" - } - return check(registerName, cacheOnly) + fun check(loginType: LoginType, cacheOnly: Boolean = false): Error? { + return check(loginType.name.lowercase(), cacheOnly) } fun check(registerName: String, cacheOnly: Boolean = false): Error? { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/MessageManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/MessageManager.kt index 996ac3bf..6b0b66fa 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/MessageManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/MessageManager.kt @@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Teacher +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.ext.appendSpan import pl.szczodrzynski.edziennik.ext.appendText @@ -149,7 +150,7 @@ class MessageManager(private val app: App) { withContext(Dispatchers.Default) { app.db.messageRecipientDao().clearFor(profileId, messageId) app.db.messageDao().delete(profileId, messageId) - app.db.metadataDao().delete(profileId, Metadata.TYPE_MESSAGE, messageId) + app.db.metadataDao().delete(profileId, MetadataType.MESSAGE, messageId) } } @@ -172,7 +173,7 @@ class MessageManager(private val app: App) { senderId = -1L, addedDate = System.currentTimeMillis(), ) - val metadata = Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true) + val metadata = Metadata(profileId, MetadataType.MESSAGE, message.id, true, true) val recipients = teachers.map { MessageRecipient(profileId, it.id, message.id) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/NavTarget.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/NavTarget.kt deleted file mode 100644 index 4e087039..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/NavTarget.kt +++ /dev/null @@ -1,97 +0,0 @@ -package pl.szczodrzynski.edziennik.utils.models - -import androidx.fragment.app.Fragment -import com.mikepenz.iconics.typeface.IIcon -import kotlin.reflect.KClass - -data class NavTarget( - val id: Int, - val name: Int, - val fragmentClass: KClass? -) { - var title: Int? = null - var icon: IIcon? = null - var description: Int? = null - var isInDrawer: Boolean = false - var isInProfileList: Boolean = false - var isStatic: Boolean = false - var isBelowSeparator: Boolean = false - var popToHome: Boolean = false - var popTo: Int? = null - var badgeTypeId: Int? = null - var canHideInDrawer: Boolean = true - var canHideInMiniDrawer: Boolean = true - var selectable: Boolean = true - var subItems: Array? = null - - fun withTitle(title: Int?): NavTarget { - this.title = title - return this - } - - fun withIcon(icon: IIcon?): NavTarget{ - this.icon = icon - return this - } - - fun withDescription(description: Int?): NavTarget { - this.description = description - return this - } - - fun isInDrawer(isInDrawer: Boolean): NavTarget { - this.isInDrawer = isInDrawer - this.popToHome = true - return this - } - - fun isInProfileList(isInProfileList: Boolean): NavTarget { - this.isInProfileList = isInProfileList - return this - } - - fun isStatic(isStatic: Boolean): NavTarget { - this.isStatic = isStatic - return this - } - - fun isBelowSeparator(isBelowSeparator: Boolean): NavTarget { - this.isBelowSeparator = isBelowSeparator - return this - } - - fun withPopToHome(popToHome: Boolean): NavTarget { - this.popToHome = popToHome - return this - } - - fun withPopTo(popTo: Int): NavTarget { - this.popTo = popTo - return this - } - - fun withBadgeTypeId(badgeTypeId: Int?): NavTarget { - this.badgeTypeId = badgeTypeId - return this - } - - fun canHideInDrawer(canHideInDrawer: Boolean): NavTarget { - this.canHideInDrawer = canHideInDrawer - return this - } - - fun canHideInMiniDrawer(canHideInMiniDrawer: Boolean): NavTarget { - this.canHideInMiniDrawer = canHideInMiniDrawer - return this - } - - fun withSelectable(selectable: Boolean): NavTarget { - this.selectable = selectable - return this - } - - fun withSubItems(vararg items: NavTarget): NavTarget { - this.subItems = items - return this - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/UnreadCounter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/UnreadCounter.kt index 73fbb1a8..a34239fb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/UnreadCounter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/UnreadCounter.kt @@ -1,14 +1,16 @@ package pl.szczodrzynski.edziennik.utils.models +import pl.szczodrzynski.edziennik.data.db.enums.MetadataType +import pl.szczodrzynski.edziennik.ext.asMetadataType import pl.szczodrzynski.navlib.drawer.IUnreadCounter class UnreadCounter : IUnreadCounter { override var profileId: Int = 0 override var count: Int = 0 - var thingType: Int = 0 + lateinit var thingType: MetadataType override var drawerItemId: Int? = null override var type: Int - get() = thingType - set(value) { thingType = value } + get() = thingType.id + set(value) { thingType = value.asMetadataType() } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3cc2451d..7109559f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -832,7 +832,7 @@ Wpis frekwencji Archiwizacja profilu Błąd - Odpowiedź na Twoje pytanie + Wiadomość od dewelopera Powiadomienie Szczęśliwy numerek Ogłoszenie szkolne From 649d4f619a32821c117b909ff6575ffc8d0f2a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 20 Oct 2022 21:59:01 +0200 Subject: [PATCH 23/53] [UI] Hide unavailable settings depending on LoginType. --- .../szczodrzynski/edziennik/MainActivity.kt | 8 +- .../edziennik/data/db/enums/FeatureType.kt | 5 +- .../edziennik/data/db/enums/LoginType.kt | 37 ++--- .../data/db/enums/LoginTypeFeatures.kt | 145 ++++++++++++++++++ .../edziennik/ext/DataExtensions.kt | 7 +- .../dialogs/settings/TimetableConfigDialog.kt | 6 +- .../ui/dialogs/sync/SyncViewListDialog.kt | 3 +- .../edziennik/ui/home/HomeFragment.kt | 13 +- .../ui/settings/cards/SettingsRegisterCard.kt | 14 +- .../edziennik/utils/BetterLink.kt | 8 +- .../res/layout/timetable_config_dialog.xml | 7 + 11 files changed, 201 insertions(+), 52 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginTypeFeatures.kt diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index 072e8550..e0e6cd3e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -33,7 +33,6 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import pl.droidsonroids.gif.GifDrawable -import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.* @@ -918,6 +917,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope { ) { d(TAG, "navigateImpl(profileId = ${profile.id}, target = ${navTarget.name}, args = $args)") + if (navTarget.featureType != null && !profile.hasUIFeature(navTarget.featureType)) { + navigateImpl(profile, NavTarget.HOME, args, profileChanged) + return + } + if (profileChanged) { App.profile = profile MessagesFragment.pageSelection = -1 @@ -1162,7 +1166,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { for (target in NavTarget.values()) { if (target.devModeOnly && !App.devMode) continue - if (target.featureType != null && target.featureType !in app.profile.loginStoreType.features) + if (target.featureType != null && !app.profile.hasUIFeature(target.featureType)) continue when (target.location) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt index 98837920..90209435 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/FeatureType.kt @@ -10,11 +10,12 @@ enum class FeatureType( val id: Int, val isAlwaysNeeded: Boolean, val nameRes: Int? = null, + val isUIAlwaysAvailable: Boolean = false, ) { TIMETABLE(id = 1, isAlwaysNeeded = false, nameRes = R.string.menu_timetable), - AGENDA(id = 2, isAlwaysNeeded = false, nameRes = R.string.menu_agenda), + AGENDA(id = 2, isAlwaysNeeded = false, nameRes = R.string.menu_agenda, isUIAlwaysAvailable = true), GRADES(id = 3, isAlwaysNeeded = false, nameRes = R.string.menu_grades), - HOMEWORK(id = 4, isAlwaysNeeded = false, nameRes = R.string.menu_homework), + HOMEWORK(id = 4, isAlwaysNeeded = false, nameRes = R.string.menu_homework, isUIAlwaysAvailable = true), BEHAVIOUR(id = 5, isAlwaysNeeded = false, nameRes = R.string.menu_notices), ATTENDANCE(id = 6, isAlwaysNeeded = false, nameRes = R.string.menu_attendance), MESSAGES_INBOX(id = 7, isAlwaysNeeded = false, nameRes = R.string.title_messages_inbox_single), diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt index ea77dd7c..9bc066d9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginType.kt @@ -4,36 +4,19 @@ package pl.szczodrzynski.edziennik.data.db.enums -import pl.szczodrzynski.edziennik.data.db.enums.FeatureType.* - -private val FEATURES_BASE = listOf( - TIMETABLE, - AGENDA, - GRADES, - HOMEWORK, -) -private val FEATURES_EXTENDED = listOf( - BEHAVIOUR, - ATTENDANCE, -) -private val FEATURES_MESSAGES = listOf( - MESSAGES_INBOX, - MESSAGES_SENT, -) - enum class LoginType( val id: Int, - val features: List, + val features: Set, ) { - MOBIDZIENNIK(id = 1, features = FEATURES_BASE + FEATURES_EXTENDED + FEATURES_MESSAGES), - LIBRUS(id = 2, features = MOBIDZIENNIK.features + ANNOUNCEMENTS), - VULCAN(id = 4, features = MOBIDZIENNIK.features), - PODLASIE(id = 6, features = FEATURES_BASE), - USOS(id = 7, features = FEATURES_BASE - GRADES), - DEMO(id = 20, features = listOf()), - TEMPLATE(id = 21, features = listOf()), + MOBIDZIENNIK(id = 1, features = FEATURES_MOBIDZIENNIK), + LIBRUS(id = 2, features = FEATURES_LIBRUS), + VULCAN(id = 4, features = FEATURES_VULCAN), + PODLASIE(id = 6, features = FEATURES_PODLASIE), + USOS(id = 7, features = FEATURES_USOS), + DEMO(id = 20, features = setOf()), + TEMPLATE(id = 21, features = setOf()), // the graveyard - EDUDZIENNIK(id = 5, features = FEATURES_BASE + FEATURES_EXTENDED), - IDZIENNIK(id = 3, features = LIBRUS.features), + EDUDZIENNIK(id = 5, features = FEATURES_EDUDZIENNIK), + IDZIENNIK(id = 3, features = FEATURES_IDZIENNIK), } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginTypeFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginTypeFeatures.kt new file mode 100644 index 00000000..b0d16002 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/LoginTypeFeatures.kt @@ -0,0 +1,145 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2022-10-20. + */ + +package pl.szczodrzynski.edziennik.data.db.enums + +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType.* + +internal val FEATURES_MOBIDZIENNIK = setOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, + BEHAVIOUR, + ATTENDANCE, + MESSAGES_INBOX, + MESSAGES_SENT, + + STUDENT_INFO, + STUDENT_NUMBER, + SCHOOL_INFO, + CLASS_INFO, + TEAM_INFO, + LUCKY_NUMBER, + TEACHERS, + SUBJECTS, + CLASSROOMS, + PUSH_CONFIG, +) + +internal val FEATURES_LIBRUS = setOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, + BEHAVIOUR, + ATTENDANCE, + MESSAGES_INBOX, + MESSAGES_SENT, + ANNOUNCEMENTS, + + STUDENT_INFO, + STUDENT_NUMBER, + SCHOOL_INFO, + CLASS_INFO, + TEAM_INFO, + LUCKY_NUMBER, + TEACHERS, + SUBJECTS, + CLASSROOMS, + PUSH_CONFIG, +) + +internal val FEATURES_VULCAN = setOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, + BEHAVIOUR, + ATTENDANCE, + MESSAGES_INBOX, + MESSAGES_SENT, + + STUDENT_INFO, + STUDENT_NUMBER, + SCHOOL_INFO, + CLASS_INFO, + TEAM_INFO, + LUCKY_NUMBER, + TEACHERS, + SUBJECTS, + CLASSROOMS, + PUSH_CONFIG, +) + +internal val FEATURES_PODLASIE = setOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, + + STUDENT_INFO, + STUDENT_NUMBER, + SCHOOL_INFO, + CLASS_INFO, + TEAM_INFO, + LUCKY_NUMBER, + TEACHERS, + SUBJECTS, + CLASSROOMS, +) + +internal val FEATURES_USOS = setOf( + TIMETABLE, + AGENDA, + + STUDENT_INFO, + STUDENT_NUMBER, + CLASS_INFO, + TEAM_INFO, + TEACHERS, + SUBJECTS, + CLASSROOMS, +) + +internal val FEATURES_EDUDZIENNIK = setOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, + BEHAVIOUR, + ATTENDANCE, + + STUDENT_INFO, + STUDENT_NUMBER, + SCHOOL_INFO, + CLASS_INFO, + TEAM_INFO, + LUCKY_NUMBER, + TEACHERS, + SUBJECTS, + CLASSROOMS, +) + +internal val FEATURES_IDZIENNIK = setOf( + TIMETABLE, + AGENDA, + GRADES, + HOMEWORK, + BEHAVIOUR, + ATTENDANCE, + MESSAGES_INBOX, + MESSAGES_SENT, + ANNOUNCEMENTS, + + STUDENT_INFO, + STUDENT_NUMBER, + SCHOOL_INFO, + CLASS_INFO, + TEAM_INFO, + LUCKY_NUMBER, + TEACHERS, + SUBJECTS, + CLASSROOMS, +) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt index 5f41af98..fc0c3fd0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/DataExtensions.kt @@ -4,16 +4,14 @@ package pl.szczodrzynski.edziennik.ext -import android.content.Context import android.util.LongSparseArray import androidx.core.util.forEach import com.google.android.material.datepicker.CalendarConstraints import com.google.gson.JsonElement -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.db.entity.Notification import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Team +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType fun List.byId(id: Long) = firstOrNull { it.id == id } fun List.byNameFirstLast(nameFirstLast: String) = firstOrNull { it.name + " " + it.surname == nameFirstLast } @@ -47,3 +45,6 @@ fun Profile.getSchoolYearConstrains(): CalendarConstraints { .setEnd(dateYearEnd.inMillisUtc) .build() } + +fun Profile.hasFeature(featureType: FeatureType) = featureType in this.loginStoreType.features +fun Profile.hasUIFeature(featureType: FeatureType) = featureType.isUIAlwaysAvailable || hasFeature(featureType) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt index b784165b..6f3cef7c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/TimetableConfigDialog.kt @@ -6,11 +6,9 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings import android.view.LayoutInflater import androidx.appcompat.app.AppCompatActivity -import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.databinding.TimetableConfigDialogBinding import pl.szczodrzynski.edziennik.ext.Intent -import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ui.dialogs.base.ConfigDialog import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment @@ -34,6 +32,10 @@ class TimetableConfigDialog( private val profileConfig by lazy { app.config.getFor(app.profileId).ui } + override fun initView() { + b.features = app.profile.loginStoreType.features + } + override suspend fun loadConfig() { b.config = profileConfig } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt index 55e185b7..50f918d7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/sync/SyncViewListDialog.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.ext.hasFeature import pl.szczodrzynski.edziennik.ext.resolveString import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.dialogs.base.BaseDialog @@ -31,7 +32,7 @@ class SyncViewListDialog( @Suppress("USELESS_CAST") override fun getMultiChoiceItems() = FeatureType.values() - .filter { it.nameRes != null } + .filter { it.nameRes != null && app.profile.hasFeature(it) } .associateBy { it.nameRes!!.resolveString(activity) as CharSequence } override fun getDefaultSelectedItems() = when (currentNavTarget) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt index 5a95c114..50240713 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/HomeFragment.kt @@ -25,9 +25,10 @@ import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.BuildConfig import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.db.entity.LoginStore +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding +import pl.szczodrzynski.edziennik.ext.hasUIFeature import pl.szczodrzynski.edziennik.ext.onClick import pl.szczodrzynski.edziennik.ui.dialogs.settings.StudentNumberDialog import pl.szczodrzynski.edziennik.ui.home.cards.* @@ -146,11 +147,11 @@ class HomeFragment : Fragment(), CoroutineScope { val cards = app.config.forProfile().ui.homeCards.filter { it.profileId == app.profile.id }.toMutableList() if (cards.isEmpty()) { - cards += listOf( - HomeCardModel(app.profile.id, HomeCard.CARD_LUCKY_NUMBER), - HomeCardModel(app.profile.id, HomeCard.CARD_TIMETABLE), - HomeCardModel(app.profile.id, HomeCard.CARD_EVENTS), - HomeCardModel(app.profile.id, HomeCard.CARD_GRADES), + cards += listOfNotNull( + HomeCardModel(app.profile.id, HomeCard.CARD_LUCKY_NUMBER).takeIf { app.profile.hasUIFeature(FeatureType.LUCKY_NUMBER) }, + HomeCardModel(app.profile.id, HomeCard.CARD_TIMETABLE).takeIf { app.profile.hasUIFeature(FeatureType.TIMETABLE) }, + HomeCardModel(app.profile.id, HomeCard.CARD_EVENTS).takeIf { app.profile.hasUIFeature(FeatureType.AGENDA) }, + HomeCardModel(app.profile.id, HomeCard.CARD_GRADES).takeIf { app.profile.hasUIFeature(FeatureType.GRADES) }, HomeCardModel(app.profile.id, HomeCard.CARD_NOTES), ) app.config.forProfile().ui.homeCards = app.config.forProfile().ui.homeCards.toMutableList().also { it.addAll(cards) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt index fc369b6a..ad405263 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/settings/cards/SettingsRegisterCard.kt @@ -9,8 +9,10 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria import eu.szkolny.font.SzkolnyFont import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.ext.after +import pl.szczodrzynski.edziennik.ext.hasUIFeature import pl.szczodrzynski.edziennik.ui.dialogs.settings.* import pl.szczodrzynski.edziennik.ui.settings.SettingsCard import pl.szczodrzynski.edziennik.ui.settings.SettingsUtil @@ -59,27 +61,29 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { icon = CommunityMaterial.Icon3.cmd_timetable ) { TimetableConfigDialog(activity, reloadOnDismiss = false).show() - }, + }.takeIf { app.profile.hasUIFeature(FeatureType.TIMETABLE) }, util.createActionItem( text = R.string.menu_agenda_config, icon = CommunityMaterial.Icon.cmd_calendar_outline ) { AgendaConfigDialog(activity, reloadOnDismiss = false).show() - }, + }.takeIf { app.profile.hasUIFeature(FeatureType.AGENDA) }, util.createActionItem( text = R.string.menu_grades_config, icon = CommunityMaterial.Icon3.cmd_numeric_5_box_outline ) { GradesConfigDialog(activity, reloadOnDismiss = false).show() - }, + }.takeIf { app.profile.hasUIFeature(FeatureType.GRADES) }, util.createActionItem( text = R.string.menu_messages_config, icon = CommunityMaterial.Icon.cmd_email_outline ) { MessagesConfigDialog(activity, reloadOnDismiss = false).show() + }.takeIf { + app.profile.hasUIFeature(FeatureType.MESSAGES_INBOX) || app.profile.hasUIFeature(FeatureType.MESSAGES_SENT) }, util.createActionItem( @@ -87,7 +91,7 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { icon = CommunityMaterial.Icon.cmd_calendar_remove_outline ) { AttendanceConfigDialog(activity, reloadOnDismiss = false).show() - }, + }.takeIf { app.profile.hasUIFeature(FeatureType.ATTENDANCE) }, if (app.profile.archived) null @@ -169,7 +173,7 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) { value = configProfile.grades.hideSticksFromOld ) { _, it -> configProfile.grades.hideSticksFromOld = it - } + }.takeIf { app.profile.hasUIFeature(FeatureType.GRADES) } else null ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt index f0cc9c13..ee6a3f65 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/BetterLink.kt @@ -24,10 +24,8 @@ import androidx.appcompat.view.menu.MenuPopupHelper import androidx.core.widget.addTextChangedListener import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.api.Regexes -import pl.szczodrzynski.edziennik.ext.Intent -import pl.szczodrzynski.edziennik.ext.copyToClipboard -import pl.szczodrzynski.edziennik.ext.get -import pl.szczodrzynski.edziennik.ext.getTextPosition +import pl.szczodrzynski.edziennik.data.db.enums.FeatureType +import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.utils.models.Date @@ -108,6 +106,8 @@ object BetterLink { } private fun createTeacherItems(menu: MenuBuilder, context: Context, teacherId: Long, fullName: String) { + if (!(context.applicationContext as App).profile.hasFeature(FeatureType.MESSAGES_INBOX)) + return menu.setTitle(fullName) menu.add( 1, diff --git a/app/src/main/res/layout/timetable_config_dialog.xml b/app/src/main/res/layout/timetable_config_dialog.xml index 19e165cf..8b724858 100644 --- a/app/src/main/res/layout/timetable_config_dialog.xml +++ b/app/src/main/res/layout/timetable_config_dialog.xml @@ -7,9 +7,15 @@ + + + + From 6c93cd421706e7382e44e011a4e785f1f4606ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 20 Oct 2022 22:02:01 +0200 Subject: [PATCH 24/53] [4.13-beta.3] Update build.gradle, signing and changelog. --- app/src/main/assets/pl-changelog.html | 3 ++- app/src/main/cpp/szkolny-signing.cpp | 2 +- .../edziennik/data/api/szkolny/interceptor/Signing.kt | 2 +- build.gradle | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index 4630e25a..d011847a 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,9 +1,10 @@ -

    Wersja 4.13-beta.2, 2022-10-18

    +

    Wersja 4.13-beta.3, 2022-10-20

    • Poprawione powiadomienia na Androidzie 13. @santoni0
    • Możliwość dostosowania wyświetlania planu lekcji
    • Opcja kolorowania bloków w planie lekcji
    • USOS - pierwsza wersja obsługi systemu
    • +
    • Poprawione opcje filtrowania powiadomień i wyboru przycisków menu bocznego.


    diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index bf07fd34..2d2527bc 100644 --- a/app/src/main/cpp/szkolny-signing.cpp +++ b/app/src/main/cpp/szkolny-signing.cpp @@ -9,7 +9,7 @@ /*secret password - removed for source code publication*/ static toys AES_IV[16] = { - 0xde, 0xd4, 0xce, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0x74, 0xc9, 0x77, 0x6d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt index 3fafc6b8..f684ea41 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/szkolny/interceptor/Signing.kt @@ -46,6 +46,6 @@ object Signing { /*fun provideKey(param1: String, param2: Long): ByteArray {*/ fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { - return "$param1.MTIzNDU2Nzg5MDl2tMYSgy===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MDoKyw75d3===.$param2".sha256() } } diff --git a/build.gradle b/build.gradle index 9dfdc8c2..e9aee798 100644 --- a/build.gradle +++ b/build.gradle @@ -5,8 +5,8 @@ buildscript { kotlin_version = '1.6.10' release = [ - versionName: "4.13-beta.2", - versionCode: 4130002 + versionName: "4.13-beta.3", + versionCode: 4130003 ] setup = [ From 63c5720f63667aaa4acc601b0f74568e56bb7ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 21 Oct 2022 23:59:53 +0200 Subject: [PATCH 25/53] [App] Move per-register settings to JSON resource. Rewrite Config to use delegates. (#150) * [App] Add base for AppData loading. * [UI] Fix timetable widget date navigation. * [UI] Migrate register-specific behavior to use AppData. * [App] Implement new delegate-based config base. * [Config] Migrate config and profile config. * [Config] Remove defaults from migrations. * [App] Apply event types and config overrides from AppData. * [Events] Change default event types for university type school. --- .idea/codeStyles/Project.xml | 7 + .idea/dictionaries/Kuba.xml | 1 + .../java/pl/szczodrzynski/edziennik/App.kt | 46 ++++- .../szczodrzynski/edziennik/MainActivity.kt | 15 +- .../edziennik/config/AbstractConfig.kt | 9 - .../szczodrzynski/edziennik/config/AppData.kt | 69 +++++++ .../edziennik/config/BaseConfig.kt | 45 +++++ .../szczodrzynski/edziennik/config/Config.kt | 142 +++----------- .../edziennik/config/ConfigGrades.kt | 13 +- .../edziennik/config/ConfigSync.kt | 150 ++++----------- .../edziennik/config/ConfigTimetable.kt | 23 +-- .../edziennik/config/ConfigUI.kt | 72 +++---- .../edziennik/config/DelegateConfig.kt | 175 +++++++++++++++++ .../edziennik/config/ProfileConfig.kt | 42 +---- .../config/ProfileConfigAttendance.kt | 28 +-- .../edziennik/config/ProfileConfigGrades.kt | 57 ++---- .../edziennik/config/ProfileConfigSync.kt | 16 +- .../edziennik/config/ProfileConfigUI.kt | 96 ++-------- .../edziennik/config/db/ConfigDao.kt | 4 +- .../config/utils/ConfigExtensions.kt | 113 ----------- .../edziennik/config/utils/ConfigGsonUtils.kt | 45 ----- .../edziennik/config/utils/ConfigMigration.kt | 68 +------ .../config/utils/ProfileConfigMigration.kt | 34 ++-- .../edziennik/data/db/dao/EventTypeDao.kt | 21 ++- .../edziennik/data/db/enums/LoginType.kt | 3 +- .../edziennik/data/db/enums/SchoolType.kt | 10 + .../edziennik/ext/DataExtensions.kt | 5 + .../edziennik/ext/JsonExtensions.kt | 22 ++- .../edziennik/ext/MiscExtensions.kt | 5 + .../edziennik/ui/agenda/AgendaFragment.kt | 4 +- .../announcements/AnnouncementsFragment.java | 6 +- .../ui/behaviour/BehaviourFragment.java | 4 +- .../edziennik/ui/behaviour/NoticesAdapter.kt | 3 +- .../edziennik/ui/home/HomeFragment.kt | 3 +- .../edziennik/ui/login/LoginSyncFragment.kt | 38 ++-- .../compose/MessagesComposeFragment.kt | 13 +- .../ui/messages/single/MessageFragment.kt | 2 +- .../ui/timetable/TimetableDayFragment.kt | 2 +- .../edziennik/ui/views/EventTypeDropdown.kt | 3 +- .../ui/widgets/WidgetConfigActivity.java | 2 +- .../timetable/WidgetTimetableProvider.kt | 6 +- app/src/main/res/raw/app_data.json | 176 ++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 43 files changed, 781 insertions(+), 818 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/config/AbstractConfig.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/config/DelegateConfig.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigExtensions.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigGsonUtils.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/enums/SchoolType.kt create mode 100644 app/src/main/res/raw/app_data.json diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index ab75be24..f7a03145 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -4,6 +4,13 @@