diff --git a/app/build.gradle b/app/build.gradle index c6e8ef86..0ceae1a1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -156,6 +156,7 @@ dependencies { implementation "androidx.navigation:navigation-fragment-ktx:2.5.2" implementation "androidx.recyclerview:recyclerview:1.2.1" implementation "androidx.room:room-runtime:2.4.3" + implementation "androidx.room:room-ktx:2.4.3" implementation "androidx.work:work-runtime-ktx:2.7.1" kapt "androidx.room:room-compiler:2.4.3" diff --git a/app/src/main/assets/pl-changelog.html b/app/src/main/assets/pl-changelog.html index 11037bae..dc0296b2 100644 --- a/app/src/main/assets/pl-changelog.html +++ b/app/src/main/assets/pl-changelog.html @@ -1,16 +1,13 @@ -

Wersja 4.13-rc.5, 2022-10-25

+

Wersja 4.13.4, 2022-12-26



Dzięki za korzystanie ze Szkolnego!
-© [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2022 +© [Kuba Szczodrzyński](@kuba2k2) 2022 diff --git a/app/src/main/cpp/szkolny-signing.cpp b/app/src/main/cpp/szkolny-signing.cpp index cdaa1ec8..fdf05a94 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] = { - 0x2f, 0xc0, 0xca, 0x16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + 0x4b, 0x43, 0x7e, 0xa2, 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/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index 30225982..cf688b03 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -422,6 +422,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { try { App.data = AppData.get(profile.loginStoreType) d("App", "Loaded AppData: ${App.data}") + // apply newly-added config overrides, if not changed by the user yet + for ((key, value) in App.data.configOverrides) { + val config = App.profile.config + if (!config.has(key)) + config.set(key, value) + } } catch (e: Exception) { Log.e("App", "Cannot load AppData", e) Toast.makeText(this, R.string.app_cannot_load_data, Toast.LENGTH_LONG).show() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt index ce39bc77..7965d17a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/MainActivity.kt @@ -322,7 +322,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope { // IT'S WINTER MY DUDES val today = Date.getToday() - if ((today.month % 11 == 1) && app.config.ui.snowfall) { + if ((today.month / 3 % 4 == 0) && app.config.ui.snowfall) { b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false)) } else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) { val eggfall = layoutInflater.inflate( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt index 6f72b82e..a0fa7c27 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/AppData.kt @@ -59,10 +59,11 @@ data class AppData( val lessonHeight: Int, val enableMarkAsReadAnnouncements: Boolean, val enableNoticePoints: Boolean, + val eventManualShowSubjectDropdown: Boolean, ) data class EventType( - val id: Int, + val id: Long, val color: String, val name: String, ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt index ac3a8af9..76d95b0b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/BaseConfig.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.ext.takePositive import kotlin.coroutines.CoroutineContext abstract class BaseConfig( + @Transient val db: AppDb, val profileId: Int? = null, protected var entries: List? = null, @@ -42,4 +43,6 @@ abstract class BaseConfig( db.configDao().add(ConfigEntry(profileId ?: -1, key, value)) } } + + fun has(key: String) = values.containsKey(key) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt index 54530a4e..2042e8b2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/Config.kt @@ -33,7 +33,7 @@ class Config(db: AppDb) : BaseConfig(db) { var update by config(null) var updatesChannel by config("release") - var devMode by config(null) + var devMode by config("debugMode", null) var devModePassword by config(null) var enableChucker by config(null) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/DelegateConfig.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/DelegateConfig.kt index 00ede071..91dac668 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/DelegateConfig.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/DelegateConfig.kt @@ -115,9 +115,9 @@ class ConfigDelegate( is Boolean -> value // enums, maps & collections is Enum<*> -> value.toInt() - is Collection<*> -> JsonArray(value.map { + is Collection<*> -> value.map { if (it is Number || it is Boolean) it else serialize(it, serializeObjects = false) - }) + }.toJsonElement() is Map<*, *> -> gson.toJson(value.mapValues { (_, it) -> if (it is Number || it is Boolean) it else serialize(it, serializeObjects = false) }) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfig.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfig.kt index 4df2ef47..c36b6fae 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfig.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfig.kt @@ -15,7 +15,7 @@ class ProfileConfig( entries: List?, ) : BaseConfig(db, profileId, entries) { companion object { - const val DATA_VERSION = 4 + const val DATA_VERSION = 5 } val grades by lazy { ProfileConfigGrades(this) } 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 4bfaf047..35951082 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigUI.kt @@ -15,6 +15,7 @@ class ProfileConfigUI(base: ProfileConfig) { var agendaGroupByType by base.config(false) var agendaLessonChanges by base.config(true) var agendaTeacherAbsence by base.config(true) + var agendaSubjectImportant by base.config(false) var agendaElearningMark by base.config(false) var agendaElearningGroup by base.config(true) 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 c5b56690..ab915b1d 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 @@ -16,6 +16,8 @@ import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_AL class ProfileConfigMigration(config: ProfileConfig) { init { config.apply { + val profile = db.profileDao().getByIdNow(profileId ?: -1) + if (dataVersion < 2) { sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE @@ -37,11 +39,23 @@ class ProfileConfigMigration(config: ProfileConfig) { // switch to new event types (USOS) dataVersion = 4 - val profile = db.profileDao().getByIdNow(profileId ?: -1) if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) { db.eventTypeDao().clear(profileId ?: -1) db.eventTypeDao().addDefaultTypes(profile) } } + + if (dataVersion < 5) { + // update USOS event types and the appropriate events (2022-12-25) + dataVersion = 5 + + if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) { + db.eventTypeDao().getAllWithDefaults(profile) + // wejściówka (4) -> kartkówka (3) + db.eventDao().getRawNow("UPDATE events SET eventType = 3 WHERE profileId = $profileId AND eventType = 4;") + // zadanie (6) -> zadanie domowe (-1) + db.eventDao().getRawNow("UPDATE events SET eventType = -1 WHERE profileId = $profileId AND eventType = 6;") + } + } }} } 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 754bbc03..83536977 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 @@ -36,7 +36,7 @@ class LibrusApiNotices(override val data: DataLibrus, val id = note.getLong("Id") ?: return@forEach val text = note.getString("Text") ?: "" val categoryId = note.getJsonObject("Category")?.getLong("Id") ?: -1 - val teacherId = note.getJsonObject("AddedBy")?.getLong("Id") ?: -1 + val teacherId = note.getJsonObject("Teacher")?.getLong("Id") ?: -1 val addedDate = note.getString("Date")?.let { Date.fromY_m_d(it) } ?: return@forEach val type = when (note.getInt("Positive")) { 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 0e50467c..e8a1e1a6 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 @@ -125,7 +125,7 @@ class LibrusMessagesGetMessage(override val data: DataLibrus, val receiverId = teacher?.id ?: -1 teacher?.loginId = receiverLoginId - val readDateText = message.select("readed").text() + val readDateText = receiver.select("readed").text() val readDate = when (readDateText.isNotNullNorEmpty()) { true -> Date.fromIso(readDateText) else -> 0 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAccountEmail.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAccountEmail.kt index 9dc3878c..6c252678 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAccountEmail.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebAccountEmail.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBID import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.ext.DAY import pl.szczodrzynski.edziennik.ext.get +import pl.szczodrzynski.edziennik.ext.isNotNullNorBlank class MobidziennikWebAccountEmail(override val data: DataMobidziennik, override val lastSync: Long?, @@ -24,7 +25,8 @@ class MobidziennikWebAccountEmail(override val data: DataMobidziennik, MobidziennikLuckyNumberExtractor(data, text) val email = Regexes.MOBIDZIENNIK_ACCOUNT_EMAIL.find(text)?.let { it[1] } - data.loginEmail = email + if (email.isNotNullNorBlank()) + data.loginEmail = email data.setSyncNext(ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL, if (email == null) 3* DAY else 7* DAY) onSuccess(ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLoginApi2.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLoginApi2.kt index 9258886b..01d7b9b7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLoginApi2.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/login/MobidziennikLoginApi2.kt @@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.ext.JsonObject import pl.szczodrzynski.edziennik.ext.getJsonObject import pl.szczodrzynski.edziennik.ext.getString +import pl.szczodrzynski.edziennik.ext.isNotNullNorBlank import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.utils.Utils @@ -77,7 +78,9 @@ class MobidziennikLoginApi2(val data: DataMobidziennik, val onSuccess: () -> Uni } } - data.loginEmail = json.getString("email") + val email = json.getString("email") + if (email.isNotNullNorBlank()) + data.loginEmail = email data.globalId = json.getString("id_global") data.loginId = json.getString("login") onSuccess() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt index a99ac7a4..83963340 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/VulcanHebe.kt @@ -26,6 +26,7 @@ import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time import java.net.HttpURLConnection +import java.net.HttpURLConnection.HTTP_NOT_FOUND import java.net.URLEncoder import java.time.Instant import java.time.LocalDateTime @@ -183,6 +184,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { payload: JsonElement? = null, baseUrl: Boolean = false, firebaseToken: String? = null, + allow404: Boolean = false, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { val url = "${if (baseUrl) data.apiUrl else data.fullApiUrl}$endpoint" @@ -295,6 +297,19 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { } override fun onFailure(response: Response?, throwable: Throwable?) { + if (allow404 && response?.code() == HTTP_NOT_FOUND) { + try { + onSuccess(null as T, response) + } catch (e: Exception) { + data.error( + ApiError(tag, EXCEPTION_VULCAN_HEBE_REQUEST) + .withResponse(response) + .withThrowable(e) + ) + } + return + } + data.error( ApiError(tag, ERROR_REQUEST_FAILURE) .withResponse(response) @@ -338,6 +353,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { query: Map = mapOf(), baseUrl: Boolean = false, firebaseToken: String? = null, + allow404: Boolean = false, crossinline onSuccess: (json: T, response: Response?) -> Unit ) { val queryPath = query.map { @@ -348,6 +364,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { if (query.isNotEmpty()) "$endpoint?$queryPath" else endpoint, baseUrl = baseUrl, firebaseToken = firebaseToken, + allow404 = allow404, onSuccess = onSuccess ) } @@ -382,6 +399,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { messageBox: String? = null, params: Map = mapOf(), includeFilterType: Boolean = true, + allow404: Boolean = false, onSuccess: (data: List, response: Response?) -> Unit ) { val url = if (includeFilterType && filterType != null) @@ -427,8 +445,8 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) { ) .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) - apiGet(tag, url, query) { json: JsonArray, response -> - onSuccess(json.map { it.asJsonObject }, response) + apiGet(tag, url, query, allow404 = allow404) { json: JsonArray?, response -> + onSuccess(json?.map { it.asJsonObject } ?: listOf(), response) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt index d7bec22b..5893486b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/hebe/VulcanHebeAddressbook.kt @@ -19,6 +19,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_PARENTS_ import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_STUDENT import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_TEACHER import pl.szczodrzynski.edziennik.ext.* +import java.net.HttpURLConnection.HTTP_NOT_FOUND class VulcanHebeAddressbook( override val data: DataVulcan, @@ -41,8 +42,15 @@ class VulcanHebeAddressbook( VULCAN_HEBE_ENDPOINT_ADDRESSBOOK, HebeFilterType.BY_PERSON, lastSync = lastSync, - includeFilterType = false - ) { list, _ -> + includeFilterType = false, + allow404 = true, + ) { list, response -> + if (response?.code() == HTTP_NOT_FOUND) { + data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK, 2 * DAY) + onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK) + return@apiGetList + } + list.forEach { person -> val id = person.getString("Id") ?: return@forEach 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 922cb6dd..954d6bb1 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 @@ -324,11 +324,14 @@ class SzkolnyApi(val app: App) : CoroutineScope { } @Throws(Exception::class) - fun shareNote(note: Note) { + fun shareNote(note: Note, teamId: Long? = null) { val profile = app.db.profileDao().getByIdNow(note.profileId) ?: throw NullPointerException("Profile is not found") - val team = app.db.teamDao().getClassNow(note.profileId) - ?: throw NullPointerException("TeamClass is not found") + val team = if (teamId == null) + app.db.teamDao().getClassNow(note.profileId) + else + app.db.teamDao().getByIdNow(note.profileId, teamId) + team ?: throw NullPointerException("TeamClass is not found") val response = api.shareNote(NoteShareRequest( deviceId = app.deviceId, 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 630fd5bd..1fe8b48b 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.MTIzNDU2Nzg5MDF1TqH/cn===.$param2".sha256() + return "$param1.MTIzNDU2Nzg5MD4BikzMWC===.$param2".sha256() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventTypeDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventTypeDao.kt index c6c9ee44..2f3f5c94 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventTypeDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/EventTypeDao.kt @@ -25,6 +25,9 @@ abstract class EventTypeDao { @Query("DELETE FROM eventTypes WHERE profileId = :profileId") abstract fun clear(profileId: Int) + @Query("DELETE FROM eventTypes WHERE profileId = :profileId AND eventTypeSource = :source") + abstract fun clearBySource(profileId: Int, source: Int) + @Query("SELECT * FROM eventTypes WHERE profileId = :profileId AND eventType = :typeId") abstract fun getByIdNow(profileId: Int, typeId: Long): EventType? @@ -43,7 +46,7 @@ abstract class EventTypeDao { val typeList = data.eventTypes.map { EventType( profileId = profile.id, - id = it.id.toLong(), + id = it.id, name = it.name, color = Color.parseColor(it.color), order = order++, @@ -53,4 +56,21 @@ abstract class EventTypeDao { addAll(typeList) return typeList } + + fun getAllWithDefaults(profile: Profile): List { + val eventTypes = getAllNow(profile.id) + + val defaultIdsExpected = AppData.get(profile.loginStoreType).eventTypes + .map { it.id } + val defaultIdsFound = eventTypes.filter { it.source == SOURCE_DEFAULT } + .sortedBy { it.order } + .map { it.id } + + if (defaultIdsExpected == defaultIdsFound) + return eventTypes + + clearBySource(profile.id, SOURCE_DEFAULT) + addDefaultTypes(profile) + return eventTypes + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/ProfileDao.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/ProfileDao.kt index ef5a3655..f83a8e76 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/ProfileDao.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/ProfileDao.kt @@ -28,6 +28,9 @@ interface ProfileDao { @Query("SELECT * FROM profiles WHERE profileId = :profileId") fun getByIdNow(profileId: Int): Profile? + @Query("SELECT * FROM profiles WHERE profileId = :profileId") + suspend fun getByIdSuspend(profileId: Int): Profile? + @get:Query("SELECT * FROM profiles WHERE profileId >= 0 ORDER BY profileId") val all: LiveData> diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EventType.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EventType.kt index 7753b38a..00ba4c04 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EventType.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/EventType.kt @@ -5,31 +5,6 @@ package pl.szczodrzynski.edziennik.data.db.entity import androidx.room.ColumnInfo import androidx.room.Entity -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_CLASS_EVENT -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_DEFAULT -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_ELEARNING -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_ESSAY -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_EXAM -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_EXCURSION -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_HOMEWORK -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_INFORMATION -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_PROJECT -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_PT_MEETING -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_READING -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_SHORT_QUIZ -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_CLASS_EVENT -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_DEFAULT -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_ELEARNING -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_ESSAY -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_EXAM -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_EXCURSION -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_HOMEWORK -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_INFORMATION -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_PROJECT -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_PT_MEETING -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_READING -import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.TYPE_SHORT_QUIZ @Entity( tableName = "eventTypes", @@ -55,35 +30,5 @@ class EventType( const val SOURCE_REGISTER = 1 const val SOURCE_CUSTOM = 2 const val SOURCE_SHARED = 3 - - fun getTypeColorMap() = mapOf( - TYPE_ELEARNING to COLOR_ELEARNING, - TYPE_HOMEWORK to COLOR_HOMEWORK, - TYPE_DEFAULT to COLOR_DEFAULT, - TYPE_EXAM to COLOR_EXAM, - TYPE_SHORT_QUIZ to COLOR_SHORT_QUIZ, - TYPE_ESSAY to COLOR_ESSAY, - TYPE_PROJECT to COLOR_PROJECT, - TYPE_PT_MEETING to COLOR_PT_MEETING, - TYPE_EXCURSION to COLOR_EXCURSION, - TYPE_READING to COLOR_READING, - TYPE_CLASS_EVENT to COLOR_CLASS_EVENT, - TYPE_INFORMATION to COLOR_INFORMATION - ) - - fun getTypeNameMap() = mapOf( - TYPE_ELEARNING to R.string.event_type_elearning, - TYPE_HOMEWORK to R.string.event_type_homework, - TYPE_DEFAULT to R.string.event_other, - TYPE_EXAM to R.string.event_exam, - TYPE_SHORT_QUIZ to R.string.event_short_quiz, - TYPE_ESSAY to R.string.event_essay, - TYPE_PROJECT to R.string.event_project, - TYPE_PT_MEETING to R.string.event_pt_meeting, - TYPE_EXCURSION to R.string.event_excursion, - TYPE_READING to R.string.event_reading, - TYPE_CLASS_EVENT to R.string.event_class_event, - TYPE_INFORMATION to R.string.event_information - ) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Noteable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Noteable.kt index 052596b3..8881c1b4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Noteable.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Noteable.kt @@ -9,6 +9,7 @@ interface Noteable { fun getNoteType(): Note.OwnerType fun getNoteOwnerProfileId(): Int fun getNoteOwnerId(): Long + fun getNoteShareTeamId(): Long? = null var notes: MutableList 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 c5d3f542..8e689883 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 @@ -91,6 +91,7 @@ open class Profile( get() = registration == REGISTRATION_ENABLED && !archived @delegate:Ignore + @delegate:Transient val config by lazy { App.config[this.id] } override fun getImageDrawable(context: Context) = this.getDrawable(context) 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 index be298b9a..64b0b7ca 100644 --- 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 @@ -6,6 +6,8 @@ package pl.szczodrzynski.edziennik.data.db.enums import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.Profile +import pl.szczodrzynski.edziennik.ext.getString +import pl.szczodrzynski.edziennik.ext.isNotNullNorBlank enum class LoginMethod( val loginType: LoginType, @@ -26,7 +28,7 @@ enum class LoginMethod( MOBIDZIENNIK_API2( loginType = LoginType.MOBIDZIENNIK, id = 1300, - isPossible = { profile, _ -> profile?.studentData?.has("email") ?: false }, + isPossible = { profile, _ -> profile?.studentData?.getString("email").isNotNullNorBlank() }, ), LIBRUS_PORTAL( loginType = LoginType.LIBRUS, @@ -57,7 +59,7 @@ enum class LoginMethod( VULCAN_WEB_MAIN( loginType = LoginType.VULCAN, id = 4100, - isPossible = { _, loginStore -> loginStore.hasLoginData("webHost") }, + isPossible = { _, loginStore -> loginStore.getLoginData("webHost", null).isNotNullNorBlank() }, ), VULCAN_HEBE( loginType = LoginType.VULCAN, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/EventFull.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/EventFull.kt index 3eb681f2..332b7ce5 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/EventFull.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/EventFull.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Event import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Note import pl.szczodrzynski.edziennik.data.db.entity.Noteable +import pl.szczodrzynski.edziennik.ext.takePositive import pl.szczodrzynski.edziennik.ui.search.Searchable import pl.szczodrzynski.edziennik.utils.html.BetterHtml import pl.szczodrzynski.edziennik.utils.models.Date @@ -118,4 +119,5 @@ class EventFull( override fun getNoteType() = Note.OwnerType.EVENT override fun getNoteOwnerProfileId() = profileId override fun getNoteOwnerId() = id + override fun getNoteShareTeamId() = teamId.takePositive() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/LessonFull.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/LessonFull.kt index cb149ce9..b61bba30 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/LessonFull.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/LessonFull.kt @@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Note import pl.szczodrzynski.edziennik.data.db.entity.Noteable +import pl.szczodrzynski.edziennik.ext.takePositive import pl.szczodrzynski.edziennik.utils.models.Time class LessonFull( @@ -142,4 +143,5 @@ class LessonFull( override fun getNoteType() = Note.OwnerType.LESSON override fun getNoteOwnerProfileId() = profileId override fun getNoteOwnerId() = ownerId + override fun getNoteShareTeamId() = teamId.takePositive() } 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 5342b330..fb261e0e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/JsonExtensions.kt @@ -5,6 +5,7 @@ package pl.szczodrzynski.edziennik.ext import android.os.Bundle +import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject @@ -48,6 +49,11 @@ fun JsonObject.putEnum(key: String, value: Enum<*>) = addProperty(key, value.toI fun String.toJsonObject(): JsonObject? = try { JsonParser.parseString(this).asJsonObject } catch (ignore: Exception) { null } fun String.toJsonArray(): JsonArray? = try { JsonParser.parseString(this).asJsonArray } catch (ignore: Exception) { null } +fun Any?.toJsonElement(): JsonElement = when (this) { + is Collection<*> -> JsonArray(this) + else -> Gson().toJsonTree(this) +} + operator fun JsonObject.set(key: String, value: JsonElement) = this.add(key, value) operator fun JsonObject.set(key: String, value: Boolean) = this.addProperty(key, value) operator fun JsonObject.set(key: String, value: String?) = this.addProperty(key, value) @@ -67,6 +73,8 @@ fun JsonObject(vararg properties: Pair): JsonObject { is Number -> addProperty(key, value) is Boolean -> addProperty(key, value) is Enum<*> -> addProperty(key, value.toInt()) + null -> add(key, null) + else -> add(key, value.toJsonElement()) } } } @@ -98,6 +106,8 @@ fun JsonArray(properties: Collection): JsonArray { is Char -> add(property as Char?) is Number -> add(property as Number?) is Boolean -> add(property as Boolean?) + is Enum<*> -> add(property.toInt()) + else -> add(property.toJsonElement()) } } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/MiscExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/MiscExtensions.kt index 5ddb5dcb..e53950f9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/MiscExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/MiscExtensions.kt @@ -76,6 +76,9 @@ fun pendingIntentFlag(): Int { fun Int?.takeValue() = if (this == -1) null else this fun Int?.takePositive() = if (this == -1 || this == 0) null else this +fun Long?.takeValue() = if (this == -1L) null else this +fun Long?.takePositive() = if (this == -1L || this == 0L) null else this + fun String?.takeValue() = if (this.isNullOrBlank()) null else this fun Any?.ignore() = Unit diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ext/ViewExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ext/ViewExtensions.kt index 3a0468ef..ddf49975 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ext/ViewExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ext/ViewExtensions.kt @@ -8,6 +8,7 @@ import android.content.Context import android.content.res.Resources import android.graphics.Rect import android.view.View +import android.view.ViewGroup import android.view.WindowManager import android.widget.* import androidx.annotation.StringRes @@ -161,3 +162,12 @@ val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener } } +fun View.removeFromParent() { + (parent as? ViewGroup)?.removeView(this) +} + +fun View.appendView(child: View) { + val parent = parent as? ViewGroup ?: return + val index = parent.indexOfChild(this) + parent.addView(child, index + 1) +} 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 52c9f345..cbdbce7b 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 @@ -142,13 +142,7 @@ class AgendaFragment : Fragment(), CoroutineScope { private suspend fun checkEventTypes() { withContext(Dispatchers.Default) { - val eventTypes = app.db.eventTypeDao().getAllNow(app.profileId).map { - it.id - } - val defaultEventTypes = EventType.getTypeColorMap().keys - if (!eventTypes.containsAll(defaultEventTypes)) { - app.db.eventTypeDao().addDefaultTypes(app.profile) - } + app.db.eventTypeDao().getAllWithDefaults(app.profile) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/event/AgendaEventRenderer.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/event/AgendaEventRenderer.kt index 31eb6730..a1b9ead4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/event/AgendaEventRenderer.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/agenda/event/AgendaEventRenderer.kt @@ -11,6 +11,7 @@ import android.widget.TextView import androidx.core.view.isVisible import com.github.tibolte.agendacalendarview.render.EventRenderer import com.mikepenz.iconics.view.IconicsTextView +import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.databinding.AgendaWrappedEventBinding import pl.szczodrzynski.edziennik.databinding.AgendaWrappedEventCompactBinding @@ -53,16 +54,24 @@ class AgendaEventRenderer( else event.time!!.stringHM + val agendaSubjectImportant = App.profile.config.ui.agendaSubjectImportant val eventSubtitle = listOfNotNull( timeText, - event.subjectLongName, + event.subjectLongName.takeIf { !agendaSubjectImportant }, + event.typeName.takeIf { agendaSubjectImportant }, event.teacherName, event.teamName ).join(", ") card.foreground.setTintColor(event.eventColor) card.background.setTintColor(event.eventColor) - manager.setEventTopic(title, event, doneIconColor = textColor) + manager.setEventTopic( + title = title, + event = event, + doneIconColor = textColor, + showType = !agendaSubjectImportant, + showSubject = agendaSubjectImportant, + ) title.setTextColor(textColor) subtitle?.text = eventSubtitle subtitle?.setTextColor(textColor) 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 5aae3c11..792811eb 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 @@ -23,6 +23,7 @@ import kotlinx.coroutines.launch import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.config.Config import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor +import pl.szczodrzynski.edziennik.data.db.entity.EventType.Companion.SOURCE_DEFAULT import pl.szczodrzynski.edziennik.databinding.LabFragmentBinding import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment @@ -65,6 +66,7 @@ class LabPageFragment : LazyFragment(), CoroutineScope { b.clearEndpointTimers.isVisible = false b.rodo.isVisible = false b.removeHomework.isVisible = false + b.resetEventTypes.isVisible = false b.unarchive.isVisible = false b.profile.isVisible = false } @@ -100,6 +102,11 @@ class LabPageFragment : LazyFragment(), CoroutineScope { app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}") } + b.resetEventTypes.onClick { + app.db.eventTypeDao().clearBySource(App.profileId, SOURCE_DEFAULT) + app.db.eventTypeDao().getAllWithDefaults(App.profile) + } + b.chucker.isChecked = App.enableChucker b.chucker.onChange { _, isChecked -> app.config.enableChucker = isChecked 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 efd8f700..30701f9c 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 @@ -113,9 +113,20 @@ class EventDetailsDialog( b.typeColor.background?.setTintColor(event.eventColor) - b.details = mutableListOf( + val agendaSubjectImportant = event.subjectLongName != null + && App.config[event.profileId].ui.agendaSubjectImportant + + b.name = if (agendaSubjectImportant) + event.subjectLongName + else + event.typeName + + b.details = listOfNotNull( + if (agendaSubjectImportant) + event.typeName + else event.subjectLongName, - event.teamName?.asColoredSpannable(colorSecondary) + event.teamName?.asColoredSpannable(colorSecondary) ).concat(bullet) b.addedBy.setText( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventListAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventListAdapter.kt index f991eeef..5c2f4eef 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventListAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventListAdapter.kt @@ -24,6 +24,7 @@ class EventListAdapter( val showDate: Boolean = false, val showColor: Boolean = true, val showType: Boolean = true, + val showTypeColor: Boolean = showType, val showTime: Boolean = true, val showSubject: Boolean = true, val markAsSeen: Boolean = true, 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 1ba200a8..49553e9a 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 @@ -19,7 +19,9 @@ import kotlinx.coroutines.withContext import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode +import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.config.AppData import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent @@ -35,9 +37,11 @@ import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding import pl.szczodrzynski.edziennik.ext.JsonObject +import pl.szczodrzynski.edziennik.ext.appendView import pl.szczodrzynski.edziennik.ext.getStudentData import pl.szczodrzynski.edziennik.ext.onChange import pl.szczodrzynski.edziennik.ext.onClick +import pl.szczodrzynski.edziennik.ext.removeFromParent import pl.szczodrzynski.edziennik.ext.setText import pl.szczodrzynski.edziennik.ext.setTintColor import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog @@ -117,6 +121,15 @@ class EventManualDialog( } override suspend fun onShow() { + val data = withContext(Dispatchers.IO) { + val profile = app.db.profileDao().getByIdSuspend(profileId) ?: return@withContext null + AppData.get(profile.loginStoreType) + } + if (data?.uiConfig?.eventManualShowSubjectDropdown == true) { + b.subjectDropdownLayout.removeFromParent() + b.timeDropdownLayout.appendView(b.subjectDropdownLayout) + } + b.showMore.onClick { // TODO iconics is broken it.apply { refreshDrawableState() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventViewHolder.kt index bee5e305..f22be345 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventViewHolder.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/event/EventViewHolder.kt @@ -113,7 +113,7 @@ class EventViewHolder( b.attachmentIcon.isVisible = item.hasAttachments b.typeColor.background?.setTintColor(item.eventColor) - b.typeColor.isVisible = adapter.showType && adapter.showColor + b.typeColor.isVisible = adapter.showTypeColor b.editButton.isVisible = !adapter.simpleMode && item.addedManually diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/CounterActivity.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/CounterActivity.kt index c63311e1..b1f10d3b 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/CounterActivity.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/home/CounterActivity.kt @@ -4,8 +4,10 @@ package pl.szczodrzynski.edziennik.ui.home +import android.graphics.BitmapFactory import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import com.jetradarmobile.snowfall.SnowfallView import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.sizeDp @@ -20,6 +22,7 @@ import pl.szczodrzynski.edziennik.ext.startCoroutineTimer import pl.szczodrzynski.edziennik.ext.timeLeft import pl.szczodrzynski.edziennik.ext.timeTill import pl.szczodrzynski.edziennik.ui.dialogs.BellSyncTimeChooseDialog +import pl.szczodrzynski.edziennik.utils.BigNightUtil import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Time import kotlin.coroutines.CoroutineContext @@ -61,6 +64,7 @@ class CounterActivity : AppCompatActivity(), CoroutineScope { it.type != Lesson.TYPE_SHIFTED_SOURCE }) } + lessonList.onEach { it.filterNotes() } } b.bellSync.setImageDrawable( @@ -81,6 +85,27 @@ class CounterActivity : AppCompatActivity(), CoroutineScope { counterJob = startCoroutineTimer(repeatMillis = 500) { update() } + + // IT'S WINTER MY DUDES + val today = Date.getToday() + if ((today.month / 3 % 4 == 0) && app.config.ui.snowfall) { + b.rootFrame.addView(layoutInflater.inflate(R.layout.snowfall, b.rootFrame, false)) + } else if (app.config.ui.eggfall && BigNightUtil().isDataWielkanocyNearDzisiaj()) { + val eggfall = layoutInflater.inflate( + R.layout.eggfall, + b.rootFrame, + false + ) as SnowfallView + eggfall.setSnowflakeBitmaps(listOf( + BitmapFactory.decodeResource(resources, R.drawable.egg1), + BitmapFactory.decodeResource(resources, R.drawable.egg2), + BitmapFactory.decodeResource(resources, R.drawable.egg3), + BitmapFactory.decodeResource(resources, R.drawable.egg4), + BitmapFactory.decodeResource(resources, R.drawable.egg5), + BitmapFactory.decodeResource(resources, R.drawable.egg6) + )) + b.rootFrame.addView(eggfall) + } }} private fun update() { @@ -101,13 +126,15 @@ class CounterActivity : AppCompatActivity(), CoroutineScope { when { actual != null -> { - b.lessonName.text = actual.displaySubjectName + b.lessonName.text = actual.getNoteSubstituteText(showNotes = true) + ?: actual.displaySubjectName val left = actual.displayEndTime!! - now b.timeLeft.text = timeLeft(left.toInt(), "\n", countInSeconds) } next != null -> { - b.lessonName.text = next.displaySubjectName + b.lessonName.text = next.getNoteSubstituteText(showNotes = true) + ?: next.displaySubjectName val till = next.displayStartTime!! - now b.timeLeft.text = timeTill(till.toInt(), "\n", countInSeconds) 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 db26d8e9..acf99b2c 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 @@ -63,9 +63,10 @@ class HomeEventsCard( simpleMode = true, showWeekDay = true, showDate = true, - showType = true, + showType = !profile.config.ui.agendaSubjectImportant, + showTypeColor = true, showTime = false, - showSubject = false, + showSubject = profile.config.ui.agendaSubjectImportant, markAsSeen = false, onEventClick = { EventDetailsDialog( 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 965fc41b..39959121 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 @@ -75,6 +75,7 @@ class HomeTimetableCard( private var counterJob: Job? = null private var counterStart: Time? = null private var counterEnd: Time? = null + private var showAllLessons: Boolean = false private var subjectSpannable: CharSequence? = null private val ignoreCancelled = false @@ -231,6 +232,7 @@ class HomeTimetableCard( } lessons = lessons.filter { it.type != Lesson.TYPE_NO_LESSONS } + lessons.onEach { it.filterNotes() } b.timetableLayout.visibility = View.VISIBLE b.noTimetableLayout.visibility = View.GONE @@ -276,6 +278,8 @@ class HomeTimetableCard( counterJob = startCoroutineTimer(repeatMillis = 500) { count() } + + showAllLessons = !isOngoing } else { val isTomorrow = today.clone().stepForward(0, 0, 1) == timetableDate @@ -312,12 +316,22 @@ class HomeTimetableCard( } ?: run { b.classroom.visibility = View.GONE } + + showAllLessons = true } val text = mutableListOf( + if (showAllLessons) + activity.getString(R.string.home_timetable_all_lessons) + else activity.getString(R.string.home_timetable_later) ) - val nextLessons = lessons.drop(skipFirst + 1) + + val nextLessons = if (showAllLessons) + lessons.drop(skipFirst) + else + lessons.drop(skipFirst + 1) + for (lesson in nextLessons) { text += listOf( lesson.displayStartTime?.stringHM, @@ -331,6 +345,7 @@ class HomeTimetableCard( private val LessonFull?.subjectSpannable: CharSequence get() = if (this == null) "?" else when { + hasReplacingNotes() -> getNoteSubstituteText(showNotes = true) ?: "?" isCancelled -> displaySubjectName?.asStrikethroughSpannable() ?: "?" isChange -> displaySubjectName?.asItalicSpannable() ?: "?" else -> displaySubjectName ?: "?" @@ -348,6 +363,14 @@ class HomeTimetableCard( } val now = syncedNow + if (now >= counterStart && showAllLessons) { + // update "next lessons" view to remove current lesson + this.counterJob?.cancel() + this.counterStart = null + this.counterEnd = null + update() + return + } if (now > counterEnd) { // the lesson is already over b.progress.visibility = View.GONE diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/notes/NoteEditorDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/notes/NoteEditorDialog.kt index df101849..8114a6db 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/notes/NoteEditorDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/notes/NoteEditorDialog.kt @@ -87,7 +87,12 @@ class NoteEditorDialog( .show() } - val success = manager.saveNote(activity, note, wasShared = editingNote?.isShared ?: false) + val success = manager.saveNote( + activity = activity, + note = note, + teamId = owner?.getNoteShareTeamId(), + wasShared = editingNote?.isShared ?: false, + ) progressDialog?.dismiss() return success } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/views/EventTypeDropdown.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/views/EventTypeDropdown.kt index d6a8d1cd..48d327fc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/views/EventTypeDropdown.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/views/EventTypeDropdown.kt @@ -33,13 +33,8 @@ class EventTypeDropdown : TextInputDropDown { suspend fun loadItems() { val types = withContext(Dispatchers.Default) { val list = mutableListOf() - - var types = db.eventTypeDao().getAllNow(profileId) - - if (types.none { it.id in -1L..10L }) { - val profile = db.profileDao().getByIdNow(profileId) ?: return@withContext listOf() - types = db.eventTypeDao().addDefaultTypes(profile) - } + val types = db.eventTypeDao().getAllNow(profileId) + .sortedBy { it.order } list += types.map { Item(it.id, it.name, tag = it, icon = IconicsDrawable(context).apply { 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 2ac510f5..10df27c3 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 @@ -337,8 +337,11 @@ class WidgetTimetableProvider : AppWidgetProvider() { scrollPos = pos + 1 } + // remove notes from other profiles + lesson.filterNotes() // set the subject and classroom name - model.subjectName = lesson.displaySubjectName + model.subjectName = lesson.getNoteSubstituteText(showNotes = true) + ?: lesson.displaySubjectName model.classroomName = lesson.displayClassroom // set the bell sync to calculate progress in ListProvider diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/EventManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/EventManager.kt index cedf3122..38a8fee3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/EventManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/EventManager.kt @@ -48,6 +48,7 @@ class EventManager(val app: App) : CoroutineScope { title: TextView, event: EventFull, showType: Boolean = true, + showSubject: Boolean = false, showNotes: Boolean = true, doneIconColor: Int? = null ) { @@ -60,6 +61,7 @@ class EventManager(val app: App) : CoroutineScope { if (event.hasNotes() && hasReplacingNotes && showNotes) "{cmd-swap-horizontal} " else null, if (event.hasNotes() && !hasReplacingNotes && showNotes) "{cmd-playlist-edit} " else null, if (showType) "${event.typeName ?: "wydarzenie"} - " else null, + if (showSubject) event.subjectLongName?.plus(" - ") else null, topicSpan, ).concat() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/NoteManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/NoteManager.kt index 67ac306b..50ac84cd 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/NoteManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/NoteManager.kt @@ -93,10 +93,15 @@ class NoteManager(private val app: App) { return getOwner(note) != null } - suspend fun saveNote(activity: AppCompatActivity, note: Note, wasShared: Boolean): Boolean { + suspend fun saveNote( + activity: AppCompatActivity, + note: Note, + teamId: Long?, + wasShared: Boolean, + ): Boolean { val success = when { !note.isShared && wasShared -> unshareNote(activity, note) - note.isShared -> shareNote(activity, note) + note.isShared -> shareNote(activity, note, teamId) else -> true } @@ -124,9 +129,9 @@ class NoteManager(private val app: App) { return true } - private suspend fun shareNote(activity: AppCompatActivity, note: Note): Boolean { + private suspend fun shareNote(activity: AppCompatActivity, note: Note, teamId: Long?): Boolean { return app.api.runCatching(activity) { - shareNote(note) + shareNote(note, teamId) } != null } @@ -166,7 +171,7 @@ class NoteManager(private val app: App) { activity = activity, simpleMode = true, showDate = true, - showColor = false, + showTypeColor = false, showTime = false, markAsSeen = false, showNotes = false, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java index 30dc4cc2..9a07ae2c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java @@ -426,4 +426,10 @@ public class Date implements Comparable, Noteable { public boolean hasReplacingNotes() { return Noteable.DefaultImpls.hasReplacingNotes(this); } + + @Nullable + @Override + public Long getNoteShareTeamId() { + return Noteable.DefaultImpls.getNoteShareTeamId(this); + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/ItemWidgetTimetableModel.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/ItemWidgetTimetableModel.java index 05c41e3b..964bee93 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/ItemWidgetTimetableModel.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/ItemWidgetTimetableModel.java @@ -19,7 +19,7 @@ public class ItemWidgetTimetableModel { public Time endTime; public boolean lessonPassed; public boolean lessonCurrent; - public String subjectName = ""; + public CharSequence subjectName = ""; public String classroomName = ""; public boolean lessonChange = false; public boolean lessonChangeNoClassroom = false; diff --git a/app/src/main/res/layout/activity_counter.xml b/app/src/main/res/layout/activity_counter.xml index 9c7f832d..77b1cde2 100644 --- a/app/src/main/res/layout/activity_counter.xml +++ b/app/src/main/res/layout/activity_counter.xml @@ -1,6 +1,9 @@ - + - + diff --git a/app/src/main/res/layout/dialog_config_agenda.xml b/app/src/main/res/layout/dialog_config_agenda.xml index 3258f656..effe23fe 100644 --- a/app/src/main/res/layout/dialog_config_agenda.xml +++ b/app/src/main/res/layout/dialog_config_agenda.xml @@ -50,6 +50,14 @@ android:minHeight="32dp" android:text="@string/agenda_config_teacher_absence" /> + + + @@ -55,7 +56,7 @@ +