Compare commits

...

22 Commits

Author SHA1 Message Date
18cc60a80b [4.13] Update build.gradle, signing and changelog. 2022-10-26 20:55:50 +02:00
fedde9f739 [UI/Home] Show all next lessons before school day start. 2022-10-26 20:34:48 +02:00
9fde97bef0 [App] Share Lesson and Event notes to specific team only. 2022-10-26 11:14:32 +02:00
742bd03e9e [Lab] Fix JSON page crashing because of serializing AppDb. 2022-10-26 10:31:03 +02:00
62ffc652ab [4.13-rc.5] Update build.gradle, signing and changelog. 2022-10-25 20:50:19 +02:00
bfd2e9883a [App] Refactor getting profile config. 2022-10-25 20:48:10 +02:00
00e077d01f [UI] Fix notes not showing in note list dialog. 2022-10-25 20:07:48 +02:00
c21d89cf60 [UI] Fix SettingsAboutCard having duplicate items. 2022-10-25 19:58:26 +02:00
f52cc1b197 [UI] Make shared notes for lessons use a stable ID. 2022-10-25 19:58:09 +02:00
c90ad97f55 [UI] Remove "enable shared events" setting. Reorder settings a bit. 2022-10-25 17:33:38 +02:00
845e09d875 [API/Usos] Add prefixes to classroom and building names. 2022-10-25 12:36:11 +02:00
158b69a8d3 [Lab] Fix full sync buttons. 2022-10-25 12:35:51 +02:00
9535f53563 [App] Refactor profile methods as extensions. 2022-10-25 12:19:59 +02:00
eeb3fc4621 [4.13-rc.4] Update build.gradle, signing and changelog. 2022-10-24 23:33:54 +02:00
41693a9fc8 [App] Respect user setting before notifying about updates. 2022-10-24 23:33:02 +02:00
d3599b8c89 [UI] Fix DateDropdown next week Friday not visible. 2022-10-24 23:32:21 +02:00
ffd81f8b82 [UI] Add setting to share events/notes by default. 2022-10-24 23:32:09 +02:00
2c34924052 [UI] Mark Firebase-received events as manual. Update legend icons. 2022-10-24 22:41:15 +02:00
26ad6373e6 [4.13-rc.3] Update build.gradle, signing and changelog. 2022-10-23 23:16:23 +02:00
cac8f94407 [Gradle] Update Chucker to fix Android 12 crash issue. 2022-10-23 23:16:08 +02:00
6628b97faf [API/Usos] Fix detecting term start and end date. 2022-10-23 23:11:49 +02:00
8424414317 [Login] Fix configOverrides NPE during login. 2022-10-23 23:11:20 +02:00
95 changed files with 3176 additions and 579 deletions

View File

@ -208,7 +208,7 @@ dependencies {
implementation "com.daimajia.swipelayout:library:1.2.0@aar" implementation "com.daimajia.swipelayout:library:1.2.0@aar"
implementation "com.github.Applandeo:Material-Calendar-View:15de569cbc" // https://github.com/Applandeo/Material-Calendar-View implementation "com.github.Applandeo:Material-Calendar-View:15de569cbc" // https://github.com/Applandeo/Material-Calendar-View
implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" // https://github.com/CanHub/Android-Image-Cropper implementation "com.github.CanHub:Android-Image-Cropper:2.2.2" // https://github.com/CanHub/Android-Image-Cropper
implementation "com.github.ChuckerTeam.Chucker:library:3.0.1" // https://github.com/ChuckerTeam/chucker implementation "com.github.ChuckerTeam.Chucker:library:3.5.2" // https://github.com/ChuckerTeam/chucker
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" // https://github.com/antonKozyriatskyi/CircularProgressIndicator implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2" // https://github.com/antonKozyriatskyi/CircularProgressIndicator
implementation "com.github.bassaer:chatmessageview:2.0.1" // https://github.com/bassaer/ChatMessageView implementation "com.github.bassaer:chatmessageview:2.0.1" // https://github.com/bassaer/ChatMessageView
implementation "com.github.hypertrack:hyperlog-android:0.0.10" // https://github.com/hypertrack/hyperlog-android implementation "com.github.hypertrack:hyperlog-android:0.0.10" // https://github.com/hypertrack/hyperlog-android

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,16 @@
<h3>Wersja 4.13-rc.2, 2022-10-22</h3> <h3>Wersja 4.13, 2022-10-26</h3>
<ul> <ul>
<li>Poprawione powiadomienia na Androidzie 13. @santoni0</li> <li>Poprawione powiadomienia na Androidzie 13. @santoni0</li>
<li>Możliwość dostosowania wyświetlania planu lekcji.</li>
<li>Opcja kolorowania bloków w planie lekcji.</li> <li>Opcja kolorowania bloków w planie lekcji.</li>
<li><b>USOS</b> - pierwsza wersja obsługi systemu. Osobne rodzaje wydarzeń (oraz wygląd niektórych części aplikacji) lepiej dostosowany do nauki na studiach.</li> <li><b>USOS</b> - pierwsza wersja obsługi systemu. Osobne rodzaje wydarzeń (oraz wygląd niektórych części aplikacji) lepiej dostosowany do nauki na studiach.</li>
<li>Możliwość dostosowania wyświetlania planu lekcji.</li>
<li>Opcja ustawienia nowych wydarzeń domyślnie jako udostępnione.</li>
<li>Poprawione udostępnianie notatek dotyczących danej lekcji</li>
<li>Bardziej czytelna legenda rodzaju udostępnionego wydarzenia.</li>
<li>Poprawione opcje filtrowania powiadomień i wyboru przycisków menu bocznego.</li> <li>Poprawione opcje filtrowania powiadomień i wyboru przycisków menu bocznego.</li>
<li>Ulepszony system pobierania aktualizacji aplikacji.</li> <li>Ulepszony system pobierania aktualizacji aplikacji.</li>
</ul> </ul>
<br> <br>
<br> <br>
Dzięki za korzystanie ze Szkolnego!<br> Dzięki za korzystanie ze Szkolnego!<br>
<i>&copy; [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2022</i> <i>&copy; [Kuba Szczodrzyński](@kuba2k2) 2022</i>

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/ /*secret password - removed for source code publication*/
static toys AES_IV[16] = { static toys AES_IV[16] = {
0x54, 0xe7, 0x2a, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0xce, 0x63, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -462,6 +462,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
} }
fun profileSave() = profileSave(profile) fun profileSave() = profileSave(profile)
fun profileSave(profile: Profile) { fun profileSave(profile: Profile) {
if (profile.id == profileId)
App.profile = profile
launch(Dispatchers.Default) { launch(Dispatchers.Default) {
App.db.profileDao().add(profile) App.db.profileDao().add(profile)
} }

View File

@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.ext.takePositive
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
abstract class BaseConfig( abstract class BaseConfig(
@Transient
val db: AppDb, val db: AppDb,
val profileId: Int? = null, val profileId: Int? = null,
protected var entries: List<ConfigEntry>? = null, protected var entries: List<ConfigEntry>? = null,

View File

@ -55,11 +55,9 @@ class Config(db: AppDb) : BaseConfig(db) {
ConfigMigration(app, this) ConfigMigration(app, this)
} }
fun getFor(profileId: Int): ProfileConfig { operator fun get(profileId: Int): ProfileConfig {
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also { return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also {
profileConfigs[profileId] = it profileConfigs[profileId] = it
} }
} }
fun forProfile() = getFor(App.profileId)
} }

View File

@ -29,6 +29,8 @@ class ProfileConfig(
var dataVersion by config<Int>(DATA_VERSION) var dataVersion by config<Int>(DATA_VERSION)
var hash by config<String>("") var hash by config<String>("")
var shareByDefault by config<Boolean>(false)
init { init {
if (dataVersion < DATA_VERSION) if (dataVersion < DATA_VERSION)
ProfileConfigMigration(this) ProfileConfigMigration(this)

View File

@ -28,6 +28,8 @@ import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.ext.isBeforeYear
import pl.szczodrzynski.edziennik.ext.shouldArchive
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type

View File

@ -52,28 +52,29 @@ class ProfileArchiver(val app: App, val profile: Profile) {
when (profile.loginStoreType) { when (profile.loginStoreType) {
LoginType.LIBRUS -> { LoginType.LIBRUS -> {
profile.removeStudentData("isPremium") profile.studentData.remove("isPremium")
profile.removeStudentData("pushDeviceId") profile.studentData.remove("pushDeviceId")
profile.removeStudentData("startPointsSemester1") profile.studentData.remove("startPointsSemester1")
profile.removeStudentData("startPointsSemester2") profile.studentData.remove("startPointsSemester2")
profile.removeStudentData("enablePointGrades") profile.studentData.remove("enablePointGrades")
profile.removeStudentData("enableDescriptiveGrades") profile.studentData.remove("enableDescriptiveGrades")
} }
LoginType.MOBIDZIENNIK -> {} LoginType.MOBIDZIENNIK -> {}
LoginType.VULCAN -> { LoginType.VULCAN -> {
// DataVulcan.isApiLoginValid() returns false so it will update the semester // DataVulcan.isApiLoginValid() returns false so it will update the semester
profile.removeStudentData("currentSemesterEndDate") profile.studentData.remove("currentSemesterEndDate")
profile.removeStudentData("studentSemesterId") profile.studentData.remove("studentSemesterId")
profile.removeStudentData("studentSemesterNumber") profile.studentData.remove("studentSemesterNumber")
profile.removeStudentData("semester1Id") profile.studentData.remove("semester1Id")
profile.removeStudentData("semester2Id") profile.studentData.remove("semester2Id")
profile.removeStudentData("studentClassId") profile.studentData.remove("studentClassId")
} }
LoginType.IDZIENNIK -> { LoginType.IDZIENNIK -> {
profile.removeStudentData("schoolYearId") profile.studentData.remove("schoolYearId")
} }
LoginType.EDUDZIENNIK -> {} LoginType.EDUDZIENNIK -> {}
LoginType.PODLASIE -> {} LoginType.PODLASIE -> {}
LoginType.USOS -> {}
LoginType.DEMO -> {} LoginType.DEMO -> {}
LoginType.TEMPLATE -> {} LoginType.TEMPLATE -> {}
} }

View File

@ -10,7 +10,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.currentTimeUnix
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.ext.set
class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) { class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
@ -117,7 +119,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiLogin: String? = null private var mApiLogin: String? = null
var apiLogin: String? var apiLogin: String?
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin } get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
set(value) { profile?.putStudentData("accountLogin", value); mApiLogin = value } set(value) { profile["accountLogin"] = value; mApiLogin = value }
/** /**
* A Synergia password. * A Synergia password.
* Used: for login (API Login Method) in Synergia mode. * Used: for login (API Login Method) in Synergia mode.
@ -126,7 +128,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPassword: String? = null private var mApiPassword: String? = null
var apiPassword: String? var apiPassword: String?
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword } get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
set(value) { profile?.putStudentData("accountPassword", value); mApiPassword = value } set(value) { profile["accountPassword"] = value; mApiPassword = value }
/** /**
* A JST login Code. * A JST login Code.
@ -135,7 +137,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiCode: String? = null private var mApiCode: String? = null
var apiCode: String? var apiCode: String?
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode } get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
set(value) { profile?.putStudentData("accountCode", value); mApiCode = value } set(value) { profile["accountCode"] = value; mApiCode = value }
/** /**
* A JST login PIN. * A JST login PIN.
* Used only during first login in JST mode. * Used only during first login in JST mode.
@ -143,7 +145,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPin: String? = null private var mApiPin: String? = null
var apiPin: String? var apiPin: String?
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin } get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
set(value) { profile?.putStudentData("accountPin", value); mApiPin = value } set(value) { profile["accountPin"] = value; mApiPin = value }
/** /**
* A Synergia API access token. * A Synergia API access token.
@ -154,7 +156,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiAccessToken: String? = null private var mApiAccessToken: String? = null
var apiAccessToken: String? var apiAccessToken: String?
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken } get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
set(value) { mApiAccessToken = value; profile?.putStudentData("accountToken", value) ?: return; } set(value) { mApiAccessToken = value; profile["accountToken"] = value ?: return; }
/** /**
* A Synergia API refresh token. * A Synergia API refresh token.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes. * Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@ -162,7 +164,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiRefreshToken: String? = null private var mApiRefreshToken: String? = null
var apiRefreshToken: String? var apiRefreshToken: String?
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken } get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
set(value) { mApiRefreshToken = value; profile?.putStudentData("accountRefreshToken", value) ?: return; } set(value) { mApiRefreshToken = value; profile["accountRefreshToken"] = value ?: return; }
/** /**
* The expiry time for [apiAccessToken], as a UNIX timestamp. * The expiry time for [apiAccessToken], as a UNIX timestamp.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes. * Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@ -171,7 +173,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiTokenExpiryTime: Long? = null private var mApiTokenExpiryTime: Long? = null
var apiTokenExpiryTime: Long var apiTokenExpiryTime: Long
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L } get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
set(value) { mApiTokenExpiryTime = value; profile?.putStudentData("accountTokenTime", value) ?: return; } set(value) { mApiTokenExpiryTime = value; profile["accountTokenTime"] = value; }
/** /**
* A push device ID, generated by Librus when registering * A push device ID, generated by Librus when registering
@ -181,7 +183,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mPushDeviceId: Int? = null private var mPushDeviceId: Int? = null
var pushDeviceId: Int var pushDeviceId: Int
get() { mPushDeviceId = mPushDeviceId ?: profile?.getStudentData("pushDeviceId", 0); return mPushDeviceId ?: 0 } get() { mPushDeviceId = mPushDeviceId ?: profile?.getStudentData("pushDeviceId", 0); return mPushDeviceId ?: 0 }
set(value) { mPushDeviceId = value; profile?.putStudentData("pushDeviceId", value) ?: return; } set(value) { mPushDeviceId = value; profile["pushDeviceId"] = value; }
/* _____ _ /* _____ _
/ ____| (_) / ____| (_)
@ -198,7 +200,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mSynergiaSessionId: String? = null private var mSynergiaSessionId: String? = null
var synergiaSessionId: String? var synergiaSessionId: String?
get() { mSynergiaSessionId = mSynergiaSessionId ?: profile?.getStudentData("accountSID", null); return mSynergiaSessionId } get() { mSynergiaSessionId = mSynergiaSessionId ?: profile?.getStudentData("accountSID", null); return mSynergiaSessionId }
set(value) { profile?.putStudentData("accountSID", value) ?: return; mSynergiaSessionId = value } set(value) { profile["accountSID"] = value; mSynergiaSessionId = value }
/** /**
* The expiry time for [synergiaSessionId], as a UNIX timestamp. * The expiry time for [synergiaSessionId], as a UNIX timestamp.
* Used in endpoints with Synergia login method. * Used in endpoints with Synergia login method.
@ -207,7 +209,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mSynergiaSessionIdExpiryTime: Long? = null private var mSynergiaSessionIdExpiryTime: Long? = null
var synergiaSessionIdExpiryTime: Long var synergiaSessionIdExpiryTime: Long
get() { mSynergiaSessionIdExpiryTime = mSynergiaSessionIdExpiryTime ?: profile?.getStudentData("accountSIDTime", 0L); return mSynergiaSessionIdExpiryTime ?: 0L } get() { mSynergiaSessionIdExpiryTime = mSynergiaSessionIdExpiryTime ?: profile?.getStudentData("accountSIDTime", 0L); return mSynergiaSessionIdExpiryTime ?: 0L }
set(value) { profile?.putStudentData("accountSIDTime", value) ?: return; mSynergiaSessionIdExpiryTime = value } set(value) { profile["accountSIDTime"] = value; mSynergiaSessionIdExpiryTime = value }
/** /**
@ -217,7 +219,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mMessagesSessionId: String? = null private var mMessagesSessionId: String? = null
var messagesSessionId: String? var messagesSessionId: String?
get() { mMessagesSessionId = mMessagesSessionId ?: profile?.getStudentData("messagesSID", null); return mMessagesSessionId } get() { mMessagesSessionId = mMessagesSessionId ?: profile?.getStudentData("messagesSID", null); return mMessagesSessionId }
set(value) { profile?.putStudentData("messagesSID", value) ?: return; mMessagesSessionId = value } set(value) { profile["messagesSID"] = value; mMessagesSessionId = value }
/** /**
* The expiry time for [messagesSessionId], as a UNIX timestamp. * The expiry time for [messagesSessionId], as a UNIX timestamp.
* Used in endpoints with Messages login method. * Used in endpoints with Messages login method.
@ -226,7 +228,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mMessagesSessionIdExpiryTime: Long? = null private var mMessagesSessionIdExpiryTime: Long? = null
var messagesSessionIdExpiryTime: Long var messagesSessionIdExpiryTime: Long
get() { mMessagesSessionIdExpiryTime = mMessagesSessionIdExpiryTime ?: profile?.getStudentData("messagesSIDTime", 0L); return mMessagesSessionIdExpiryTime ?: 0L } get() { mMessagesSessionIdExpiryTime = mMessagesSessionIdExpiryTime ?: profile?.getStudentData("messagesSIDTime", 0L); return mMessagesSessionIdExpiryTime ?: 0L }
set(value) { profile?.putStudentData("messagesSIDTime", value) ?: return; mMessagesSessionIdExpiryTime = value } set(value) { profile["messagesSIDTime"] = value; mMessagesSessionIdExpiryTime = value }
/* ____ _ _ /* ____ _ _
/ __ \| | | | / __ \| | | |
@ -236,42 +238,42 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
\____/ \__|_| |_|\___|*/ \____/ \__|_| |_|\___|*/
var isPremium var isPremium
get() = profile?.getStudentData("isPremium", false) ?: false get() = profile?.getStudentData("isPremium", false) ?: false
set(value) { profile?.putStudentData("isPremium", value) } set(value) { profile["isPremium"] = value }
private var mSchoolName: String? = null private var mSchoolName: String? = null
var schoolName: String? var schoolName: String?
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName } get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value } set(value) { profile["schoolName"] = value; mSchoolName = value }
private var mUnitId: Long? = null private var mUnitId: Long? = null
var unitId: Long var unitId: Long
get() { mUnitId = mUnitId ?: profile?.getStudentData("unitId", 0L); return mUnitId ?: 0L } get() { mUnitId = mUnitId ?: profile?.getStudentData("unitId", 0L); return mUnitId ?: 0L }
set(value) { profile?.putStudentData("unitId", value) ?: return; mUnitId = value } set(value) { profile["unitId"] = value; mUnitId = value }
private var mStartPointsSemester1: Int? = null private var mStartPointsSemester1: Int? = null
var startPointsSemester1: Int var startPointsSemester1: Int
get() { mStartPointsSemester1 = mStartPointsSemester1 ?: profile?.getStudentData("startPointsSemester1", 0); return mStartPointsSemester1 ?: 0 } get() { mStartPointsSemester1 = mStartPointsSemester1 ?: profile?.getStudentData("startPointsSemester1", 0); return mStartPointsSemester1 ?: 0 }
set(value) { profile?.putStudentData("startPointsSemester1", value) ?: return; mStartPointsSemester1 = value } set(value) { profile["startPointsSemester1"] = value; mStartPointsSemester1 = value }
private var mStartPointsSemester2: Int? = null private var mStartPointsSemester2: Int? = null
var startPointsSemester2: Int var startPointsSemester2: Int
get() { mStartPointsSemester2 = mStartPointsSemester2 ?: profile?.getStudentData("startPointsSemester2", 0); return mStartPointsSemester2 ?: 0 } get() { mStartPointsSemester2 = mStartPointsSemester2 ?: profile?.getStudentData("startPointsSemester2", 0); return mStartPointsSemester2 ?: 0 }
set(value) { profile?.putStudentData("startPointsSemester2", value) ?: return; mStartPointsSemester2 = value } set(value) { profile["startPointsSemester2"] = value; mStartPointsSemester2 = value }
private var mEnablePointGrades: Boolean? = null private var mEnablePointGrades: Boolean? = null
var enablePointGrades: Boolean var enablePointGrades: Boolean
get() { mEnablePointGrades = mEnablePointGrades ?: profile?.getStudentData("enablePointGrades", true); return mEnablePointGrades ?: true } get() { mEnablePointGrades = mEnablePointGrades ?: profile?.getStudentData("enablePointGrades", true); return mEnablePointGrades ?: true }
set(value) { profile?.putStudentData("enablePointGrades", value) ?: return; mEnablePointGrades = value } set(value) { profile["enablePointGrades"] = value; mEnablePointGrades = value }
private var mEnableDescriptiveGrades: Boolean? = null private var mEnableDescriptiveGrades: Boolean? = null
var enableDescriptiveGrades: Boolean var enableDescriptiveGrades: Boolean
get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true } get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true }
set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value } set(value) { profile["enableDescriptiveGrades"] = value; mEnableDescriptiveGrades = value }
private var mTimetableNotPublic: Boolean? = null private var mTimetableNotPublic: Boolean? = null
var timetableNotPublic: Boolean var timetableNotPublic: Boolean
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false } get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value } set(value) { profile["timetableNotPublic"] = value; mTimetableNotPublic = value }
/** /**
* Set to false when Recaptcha helper doesn't provide a working token. * Set to false when Recaptcha helper doesn't provide a working token.

View File

@ -190,6 +190,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
} }
lessonObject.id = lessonObject.buildId() lessonObject.id = lessonObject.buildId()
lessonObject.ownerId = lessonObject.buildOwnerId()
val seen = profile.empty || lessonDate < Date.getToday() val seen = profile.empty || lessonDate < Date.getToday()

View File

@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.HOUR import pl.szczodrzynski.edziennik.ext.HOUR
import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.get
import pl.szczodrzynski.edziennik.ext.getSemesterStart
import pl.szczodrzynski.edziennik.ext.singleOrNull import pl.szczodrzynski.edziennik.ext.singleOrNull
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date

View File

@ -11,7 +11,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.currentTimeUnix
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.ext.set
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
@ -85,7 +87,7 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da
private var mStudentId: Int? = null private var mStudentId: Int? = null
var studentId: Int var studentId: Int
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 } get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 }
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } set(value) { profile["studentId"] = value; mStudentId = value }
/* __ __ _ /* __ __ _
\ \ / / | | \ \ / / | |
@ -125,7 +127,7 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da
*/ */
var globalId: String? var globalId: String?
get() { mGlobalId = mGlobalId ?: profile?.getStudentData("globalId", null); return mGlobalId } get() { mGlobalId = mGlobalId ?: profile?.getStudentData("globalId", null); return mGlobalId }
set(value) { profile?.putStudentData("globalId", value) ?: return; mGlobalId = value } set(value) { profile["globalId"] = value; mGlobalId = value }
private var mGlobalId: String? = null private var mGlobalId: String? = null
/** /**
@ -135,7 +137,7 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da
*/ */
var loginEmail: String? var loginEmail: String?
get() { mLoginEmail = mLoginEmail ?: profile?.getStudentData("email", null); return mLoginEmail } get() { mLoginEmail = mLoginEmail ?: profile?.getStudentData("email", null); return mLoginEmail }
set(value) { profile?.putStudentData("email", value); mLoginEmail = value } set(value) { profile["email"] = value; mLoginEmail = value }
private var mLoginEmail: String? = null private var mLoginEmail: String? = null
/** /**
@ -144,7 +146,7 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da
*/ */
var loginId: String? var loginId: String?
get() { mLoginId = mLoginId ?: profile?.getStudentData("loginId", null); return mLoginId } get() { mLoginId = mLoginId ?: profile?.getStudentData("loginId", null); return mLoginId }
set(value) { profile?.putStudentData("loginId", value) ?: return; mLoginId = value } set(value) { profile["loginId"] = value; mLoginId = value }
private var mLoginId: String? = null private var mLoginId: String? = null
/** /**
@ -152,7 +154,7 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da
*/ */
var ciasteczkoAutoryzacji: String? var ciasteczkoAutoryzacji: String?
get() { mCiasteczkoAutoryzacji = mCiasteczkoAutoryzacji ?: profile?.getStudentData("ciasteczkoAutoryzacji", null); return mCiasteczkoAutoryzacji } get() { mCiasteczkoAutoryzacji = mCiasteczkoAutoryzacji ?: profile?.getStudentData("ciasteczkoAutoryzacji", null); return mCiasteczkoAutoryzacji }
set(value) { profile?.putStudentData("ciasteczkoAutoryzacji", value) ?: return; mCiasteczkoAutoryzacji = value } set(value) { profile["ciasteczkoAutoryzacji"] = value; mCiasteczkoAutoryzacji = value }
private var mCiasteczkoAutoryzacji: String? = null private var mCiasteczkoAutoryzacji: String? = null

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESE
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED 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.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.dateToSemester
class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>) { class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>) {
init { run { init { run {

View File

@ -88,6 +88,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
} }
it.id = it.buildId() it.id = it.buildId()
it.ownerId = it.buildOwnerId()
val seen = profile.empty || date < Date.getToday() val seen = profile.empty || date < Date.getToday()

View File

@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNO
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.dateToSemester
import pl.szczodrzynski.edziennik.ext.fixName import pl.szczodrzynski.edziennik.ext.fixName
import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.get
import pl.szczodrzynski.edziennik.ext.singleOrNull import pl.szczodrzynski.edziennik.ext.singleOrNull

View File

@ -15,6 +15,7 @@ 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.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.dateToSemester
import pl.szczodrzynski.edziennik.ext.fixWhiteSpaces import pl.szczodrzynski.edziennik.ext.fixWhiteSpaces
import pl.szczodrzynski.edziennik.ext.get import pl.szczodrzynski.edziennik.ext.get
import pl.szczodrzynski.edziennik.ext.singleOrNull import pl.szczodrzynski.edziennik.ext.singleOrNull

View File

@ -336,6 +336,7 @@ class MobidziennikWebTimetable(
} }
it.id = it.buildId() it.id = it.buildId()
it.ownerId = it.buildOwnerId()
it.isExtra = isExtra it.isExtra = isExtra
val seen = profile?.empty == false || lessonDate < Date.getToday() val seen = profile?.empty == false || lessonDate < Date.getToday()

View File

@ -10,7 +10,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.crc32 import pl.szczodrzynski.edziennik.ext.crc32
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.ext.set
class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) { class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
@ -40,7 +42,7 @@ class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(a
private var mApiUrl: String? = null private var mApiUrl: String? = null
var apiUrl: String? var apiUrl: String?
get() { mApiUrl = mApiUrl ?: profile?.getStudentData("apiUrl", null); return mApiUrl } get() { mApiUrl = mApiUrl ?: profile?.getStudentData("apiUrl", null); return mApiUrl }
set(value) { profile?.putStudentData("apiUrl", value) ?: return; mApiUrl = value } set(value) { profile["apiUrl"] = value; mApiUrl = value }
/* ____ _ _ /* ____ _ _
/ __ \| | | | / __ \| | | |
@ -51,32 +53,32 @@ class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(a
private var mStudentId: String? = null private var mStudentId: String? = null
var studentId: String? var studentId: String?
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId } get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } set(value) { profile["studentId"] = value; mStudentId = value }
private var mStudentLogin: String? = null private var mStudentLogin: String? = null
var studentLogin: String? var studentLogin: String?
get() { mStudentLogin = mStudentLogin ?: profile?.getStudentData("studentLogin", null); return mStudentLogin } get() { mStudentLogin = mStudentLogin ?: profile?.getStudentData("studentLogin", null); return mStudentLogin }
set(value) { profile?.putStudentData("studentLogin", value) ?: return; mStudentLogin = value } set(value) { profile["studentLogin"] = value; mStudentLogin = value }
private var mSchoolName: String? = null private var mSchoolName: String? = null
var schoolName: String? var schoolName: String?
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName } get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value } set(value) { profile["schoolName"] = value; mSchoolName = value }
private var mClassName: String? = null private var mClassName: String? = null
var className: String? var className: String?
get() { mClassName = mClassName ?: profile?.getStudentData("className", null); return mClassName } get() { mClassName = mClassName ?: profile?.getStudentData("className", null); return mClassName }
set(value) { profile?.putStudentData("className", value) ?: return; mClassName = value } set(value) { profile["className"] = value; mClassName = value }
private var mSchoolYear: String? = null private var mSchoolYear: String? = null
var schoolYear: String? var schoolYear: String?
get() { mSchoolYear = mSchoolYear ?: profile?.getStudentData("schoolYear", null); return mSchoolYear } get() { mSchoolYear = mSchoolYear ?: profile?.getStudentData("schoolYear", null); return mSchoolYear }
set(value) { profile?.putStudentData("schoolYear", value) ?: return; mSchoolYear = value } set(value) { profile["schoolYear"] = value; mSchoolYear = value }
private var mCurrentSemester: Int? = null private var mCurrentSemester: Int? = null
var currentSemester: Int var currentSemester: Int
get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 0); return mCurrentSemester ?: 0 } get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 0); return mCurrentSemester ?: 0 }
set(value) { profile?.putStudentData("currentSemester", value) ?: return; mCurrentSemester = value } set(value) { profile["currentSemester"] = value; mCurrentSemester = value }
val schoolShortName: String? val schoolShortName: String?
get() = studentLogin?.split('@')?.get(1)?.replace(".podlaskie.pl", "") get() = studentLogin?.split('@')?.get(1)?.replace(".podlaskie.pl", "")

View File

@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPO
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getLong
import pl.szczodrzynski.edziennik.ext.getSemesterStart
import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.getString
class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List<JsonObject>) { class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List<JsonObject>) {

View File

@ -72,6 +72,7 @@ class PodlasieApiTimetable(val data: DataPodlasie, rows: List<JsonObject>) {
it.classroom = classroom it.classroom = classroom
it.id = it.buildId() it.id = it.buildId()
it.ownerId = it.buildOwnerId()
data.lessonList += it data.lessonList += it
} }
} }

View File

@ -10,7 +10,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.currentTimeUnix
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.ext.set
/** /**
* Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art * Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
@ -43,12 +45,12 @@ class DataTemplate(app: App, profile: Profile?, loginStore: LoginStore) : Data(a
private var mWebCookie: String? = null private var mWebCookie: String? = null
var webCookie: String? var webCookie: String?
get() { mWebCookie = mWebCookie ?: profile?.getStudentData("webCookie", null); return mWebCookie } get() { mWebCookie = mWebCookie ?: profile?.getStudentData("webCookie", null); return mWebCookie }
set(value) { profile?.putStudentData("webCookie", value) ?: return; mWebCookie = value } set(value) { profile["webCookie"] = value; mWebCookie = value }
private var mWebExpiryTime: Long? = null private var mWebExpiryTime: Long? = null
var webExpiryTime: Long var webExpiryTime: Long
get() { mWebExpiryTime = mWebExpiryTime ?: profile?.getStudentData("webExpiryTime", 0L); return mWebExpiryTime ?: 0L } get() { mWebExpiryTime = mWebExpiryTime ?: profile?.getStudentData("webExpiryTime", 0L); return mWebExpiryTime ?: 0L }
set(value) { profile?.putStudentData("webExpiryTime", value) ?: return; mWebExpiryTime = value } set(value) { profile["webExpiryTime"] = value; mWebExpiryTime = value }
/* _ /* _
/\ (_) /\ (_)
@ -61,10 +63,10 @@ class DataTemplate(app: App, profile: Profile?, loginStore: LoginStore) : Data(a
private var mApiToken: String? = null private var mApiToken: String? = null
var apiToken: String? var apiToken: String?
get() { mApiToken = mApiToken ?: profile?.getStudentData("apiToken", null); return mApiToken } get() { mApiToken = mApiToken ?: profile?.getStudentData("apiToken", null); return mApiToken }
set(value) { profile?.putStudentData("apiToken", value) ?: return; mApiToken = value } set(value) { profile["apiToken"] = value; mApiToken = value }
private var mApiExpiryTime: Long? = null private var mApiExpiryTime: Long? = null
var apiExpiryTime: Long var apiExpiryTime: Long
get() { mApiExpiryTime = mApiExpiryTime ?: profile?.getStudentData("apiExpiryTime", 0L); return mApiExpiryTime ?: 0L } get() { mApiExpiryTime = mApiExpiryTime ?: profile?.getStudentData("apiExpiryTime", 0L); return mApiExpiryTime ?: 0L }
set(value) { profile?.putStudentData("apiExpiryTime", value) ?: return; mApiExpiryTime = value } set(value) { profile["apiExpiryTime"] = value; mApiExpiryTime = value }
} }

View File

@ -9,6 +9,8 @@ import pl.szczodrzynski.edziennik.data.api.models.Data
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.set
class DataUsos( class DataUsos(
app: App, app: App,
@ -69,6 +71,6 @@ class DataUsos(
var studentId: Int var studentId: Int
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 } get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 }
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } set(value) { profile["studentId"] = value; mStudentId = value }
private var mStudentId: Int? = null private var mStudentId: Int? = null
} }

View File

@ -41,24 +41,18 @@ class UsosApiTerms(
} }
private fun processResponse(json: JsonArray): Boolean { private fun processResponse(json: JsonArray): Boolean {
val dates = mutableSetOf<Date>() val today = Date.getToday()
for (term in json.asJsonObjectList()) { for (term in json.asJsonObjectList()) {
if (!term.getBoolean("is_active", false)) if (!term.getBoolean("is_active", false))
continue continue
val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) } val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) } ?: continue
val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) } val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) } ?: continue
if (startDate != null) if (today in startDate..finishDate) {
dates += startDate profile?.studentSchoolYearStart = startDate.year
if (finishDate != null) profile?.dateSemester1Start = startDate
dates += finishDate profile?.dateSemester2Start = 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 return true
} }
} }

View File

@ -104,8 +104,9 @@ class UsosApiTimetable(
it.teacherId = lecturerIds?.firstOrNull() ?: -1L it.teacherId = lecturerIds?.firstOrNull() ?: -1L
it.teamId = unitId it.teamId = unitId
val groupName = classTypeId?.plus(groupNumber)?.let { s -> "($s)" } val groupName = classTypeId?.plus(groupNumber)?.let { s -> "($s)" }
it.classroom = "$buildingId / $roomNumber ${groupName ?: ""}" it.classroom = "Sala $roomNumber / bud. $buildingId ${groupName ?: ""}"
it.id = it.buildId() it.id = it.buildId()
it.ownerId = it.buildOwnerId()
it.color = when (classTypeId) { it.color = when (classTypeId) {
"WYK" -> 0xff0d6091 "WYK" -> 0xff0d6091

View File

@ -12,7 +12,9 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod import pl.szczodrzynski.edziennik.data.db.enums.LoginMethod
import pl.szczodrzynski.edziennik.ext.crc16 import pl.szczodrzynski.edziennik.ext.crc16
import pl.szczodrzynski.edziennik.ext.currentTimeUnix import pl.szczodrzynski.edziennik.ext.currentTimeUnix
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.ext.set
import pl.szczodrzynski.fslogin.realm.RealmData import pl.szczodrzynski.fslogin.realm.RealmData
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) { class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
@ -57,7 +59,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mSymbol: String? = null private var mSymbol: String? = null
var symbol: String? var symbol: String?
get() { mSymbol = mSymbol ?: profile?.getStudentData("symbol", null); return mSymbol } get() { mSymbol = mSymbol ?: profile?.getStudentData("symbol", null); return mSymbol }
set(value) { profile?.putStudentData("symbol", value); mSymbol = value } set(value) { profile["symbol"] = value; mSymbol = value }
/** /**
* Group symbol/number of the student's school. * Group symbol/number of the student's school.
@ -69,7 +71,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mSchoolSymbol: String? = null private var mSchoolSymbol: String? = null
var schoolSymbol: String? var schoolSymbol: String?
get() { mSchoolSymbol = mSchoolSymbol ?: profile?.getStudentData("schoolSymbol", null); return mSchoolSymbol } get() { mSchoolSymbol = mSchoolSymbol ?: profile?.getStudentData("schoolSymbol", null); return mSchoolSymbol }
set(value) { profile?.putStudentData("schoolSymbol", value) ?: return; mSchoolSymbol = value } set(value) { profile["schoolSymbol"] = value; mSchoolSymbol = value }
/** /**
* Short name of the school, used in some places. * Short name of the school, used in some places.
@ -79,7 +81,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mSchoolShort: String? = null private var mSchoolShort: String? = null
var schoolShort: String? var schoolShort: String?
get() { mSchoolShort = mSchoolShort ?: profile?.getStudentData("schoolShort", null); return mSchoolShort } get() { mSchoolShort = mSchoolShort ?: profile?.getStudentData("schoolShort", null); return mSchoolShort }
set(value) { profile?.putStudentData("schoolShort", value) ?: return; mSchoolShort = value } set(value) { profile["schoolShort"] = value; mSchoolShort = value }
/** /**
* A school code consisting of the [symbol] and [schoolSymbol]. * A school code consisting of the [symbol] and [schoolSymbol].
@ -91,7 +93,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mSchoolCode: String? = null private var mSchoolCode: String? = null
var schoolCode: String? var schoolCode: String?
get() { mSchoolCode = mSchoolCode ?: profile?.getStudentData("schoolName", null); return mSchoolCode } get() { mSchoolCode = mSchoolCode ?: profile?.getStudentData("schoolName", null); return mSchoolCode }
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolCode = value } set(value) { profile["schoolName"] = value; mSchoolCode = value }
/** /**
* ID of the student. * ID of the student.
@ -101,7 +103,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mStudentId: Int? = null private var mStudentId: Int? = null
var studentId: Int var studentId: Int
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 } get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 }
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value } set(value) { profile["studentId"] = value; mStudentId = value }
/** /**
* ID of the student's account. * ID of the student's account.
@ -111,7 +113,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mStudentLoginId: Int? = null private var mStudentLoginId: Int? = null
var studentLoginId: Int var studentLoginId: Int
get() { mStudentLoginId = mStudentLoginId ?: profile?.getStudentData("studentLoginId", 0); return mStudentLoginId ?: 0 } get() { mStudentLoginId = mStudentLoginId ?: profile?.getStudentData("studentLoginId", 0); return mStudentLoginId ?: 0 }
set(value) { profile?.putStudentData("studentLoginId", value) ?: return; mStudentLoginId = value } set(value) { profile["studentLoginId"] = value; mStudentLoginId = value }
/** /**
* ID of the student's class. * ID of the student's class.
@ -121,7 +123,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mStudentClassId: Int? = null private var mStudentClassId: Int? = null
var studentClassId: Int var studentClassId: Int
get() { mStudentClassId = mStudentClassId ?: profile?.getStudentData("studentClassId", 0); return mStudentClassId ?: 0 } get() { mStudentClassId = mStudentClassId ?: profile?.getStudentData("studentClassId", 0); return mStudentClassId ?: 0 }
set(value) { profile?.putStudentData("studentClassId", value) ?: return; mStudentClassId = value } set(value) { profile["studentClassId"] = value; mStudentClassId = value }
/** /**
* ListaUczniow/IdOkresKlasyfikacyjny, e.g. 321 * ListaUczniow/IdOkresKlasyfikacyjny, e.g. 321
@ -129,26 +131,26 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mStudentSemesterId: Int? = null private var mStudentSemesterId: Int? = null
var studentSemesterId: Int var studentSemesterId: Int
get() { mStudentSemesterId = mStudentSemesterId ?: profile?.getStudentData("studentSemesterId", 0); return mStudentSemesterId ?: 0 } get() { mStudentSemesterId = mStudentSemesterId ?: profile?.getStudentData("studentSemesterId", 0); return mStudentSemesterId ?: 0 }
set(value) { profile?.putStudentData("studentSemesterId", value) ?: return; mStudentSemesterId = value } set(value) { profile["studentSemesterId"] = value; mStudentSemesterId = value }
private var mStudentUnitId: Int? = null private var mStudentUnitId: Int? = null
var studentUnitId: Int var studentUnitId: Int
get() { mStudentUnitId = mStudentUnitId ?: profile?.getStudentData("studentUnitId", 0); return mStudentUnitId ?: 0 } get() { mStudentUnitId = mStudentUnitId ?: profile?.getStudentData("studentUnitId", 0); return mStudentUnitId ?: 0 }
set(value) { profile?.putStudentData("studentUnitId", value) ?: return; mStudentUnitId = value } set(value) { profile["studentUnitId"] = value; mStudentUnitId = value }
private var mStudentConstituentId: Int? = null private var mStudentConstituentId: Int? = null
var studentConstituentId: Int var studentConstituentId: Int
get() { mStudentConstituentId = mStudentConstituentId ?: profile?.getStudentData("studentConstituentId", 0); return mStudentConstituentId ?: 0 } get() { mStudentConstituentId = mStudentConstituentId ?: profile?.getStudentData("studentConstituentId", 0); return mStudentConstituentId ?: 0 }
set(value) { profile?.putStudentData("studentConstituentId", value) ?: return; mStudentConstituentId = value } set(value) { profile["studentConstituentId"] = value; mStudentConstituentId = value }
private var mSemester1Id: Int? = null private var mSemester1Id: Int? = null
var semester1Id: Int var semester1Id: Int
get() { mSemester1Id = mSemester1Id ?: profile?.getStudentData("semester1Id", 0); return mSemester1Id ?: 0 } get() { mSemester1Id = mSemester1Id ?: profile?.getStudentData("semester1Id", 0); return mSemester1Id ?: 0 }
set(value) { profile?.putStudentData("semester1Id", value) ?: return; mSemester1Id = value } set(value) { profile["semester1Id"] = value; mSemester1Id = value }
private var mSemester2Id: Int? = null private var mSemester2Id: Int? = null
var semester2Id: Int var semester2Id: Int
get() { mSemester2Id = mSemester2Id ?: profile?.getStudentData("semester2Id", 0); return mSemester2Id ?: 0 } get() { mSemester2Id = mSemester2Id ?: profile?.getStudentData("semester2Id", 0); return mSemester2Id ?: 0 }
set(value) { profile?.putStudentData("semester2Id", value) ?: return; mSemester2Id = value } set(value) { profile["semester2Id"] = value; mSemester2Id = value }
/** /**
* ListaUczniow/OkresNumer, e.g. 1 or 2 * ListaUczniow/OkresNumer, e.g. 1 or 2
@ -156,7 +158,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mStudentSemesterNumber: Int? = null private var mStudentSemesterNumber: Int? = null
var studentSemesterNumber: Int var studentSemesterNumber: Int
get() { mStudentSemesterNumber = mStudentSemesterNumber ?: profile?.getStudentData("studentSemesterNumber", 0); return mStudentSemesterNumber ?: 0 } get() { mStudentSemesterNumber = mStudentSemesterNumber ?: profile?.getStudentData("studentSemesterNumber", 0); return mStudentSemesterNumber ?: 0 }
set(value) { profile?.putStudentData("studentSemesterNumber", value) ?: return; mStudentSemesterNumber = value } set(value) { profile["studentSemesterNumber"] = value; mStudentSemesterNumber = value }
/** /**
* Date of the end of the current semester ([studentSemesterNumber]). * Date of the end of the current semester ([studentSemesterNumber]).
@ -166,7 +168,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mCurrentSemesterEndDate: Long? = null private var mCurrentSemesterEndDate: Long? = null
var currentSemesterEndDate: Long var currentSemesterEndDate: Long
get() { mCurrentSemesterEndDate = mCurrentSemesterEndDate ?: profile?.getStudentData("currentSemesterEndDate", 0L); return mCurrentSemesterEndDate ?: 0L } get() { mCurrentSemesterEndDate = mCurrentSemesterEndDate ?: profile?.getStudentData("currentSemesterEndDate", 0L); return mCurrentSemesterEndDate ?: 0L }
set(value) { profile?.putStudentData("currentSemesterEndDate", value) ?: return; mCurrentSemesterEndDate = value } set(value) { profile["currentSemesterEndDate"] = value; mCurrentSemesterEndDate = value }
/* _____ _____ ____ /* _____ _____ ____
/\ | __ \_ _| |___ \ /\ | __ \_ _| |___ \
@ -219,17 +221,17 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mHebeContext: String? = null private var mHebeContext: String? = null
var hebeContext: String? var hebeContext: String?
get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext } get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext }
set(value) { profile?.putStudentData("hebeContext", value) ?: return; mHebeContext = value } set(value) { profile["hebeContext"] = value; mHebeContext = value }
private var mMessageBoxKey: String? = null private var mMessageBoxKey: String? = null
var messageBoxKey: String? var messageBoxKey: String?
get() { mMessageBoxKey = mMessageBoxKey ?: profile?.getStudentData("messageBoxKey", null); return mMessageBoxKey } get() { mMessageBoxKey = mMessageBoxKey ?: profile?.getStudentData("messageBoxKey", null); return mMessageBoxKey }
set(value) { profile?.putStudentData("messageBoxKey", value) ?: return; mMessageBoxKey = value } set(value) { profile["messageBoxKey"] = value; mMessageBoxKey = value }
private var mMessageBoxName: String? = null private var mMessageBoxName: String? = null
var messageBoxName: String? var messageBoxName: String?
get() { mMessageBoxName = mMessageBoxName ?: profile?.getStudentData("messageBoxName", null); return mMessageBoxName } get() { mMessageBoxName = mMessageBoxName ?: profile?.getStudentData("messageBoxName", null); return mMessageBoxName }
set(value) { profile?.putStudentData("messageBoxName", value) ?: return; mMessageBoxName = value } set(value) { profile["messageBoxName"] = value; mMessageBoxName = value }
val apiUrl: String? val apiUrl: String?
get() { get() {

View File

@ -247,7 +247,9 @@ class VulcanHebeTimetable(
} }
lessonObject.id = lessonObject.buildId() lessonObject.id = lessonObject.buildId()
lessonObject.ownerId = lessonObject.buildOwnerId()
lessonShift?.id = lessonShift?.buildId() ?: -1 lessonShift?.id = lessonShift?.buildId() ?: -1
lessonShift?.ownerId = lessonShift?.buildOwnerId() ?: -1
lessonList.add(lessonObject) lessonList.add(lessonObject)
lessonShift?.let { lessonList.add(it) } lessonShift?.let { lessonList.add(it) }

View File

@ -198,7 +198,6 @@ class SzkolnyApi(val app: App) : CoroutineScope {
val teams = app.db.teamDao().allNow val teams = app.db.teamDao().allNow
val users = profiles.mapNotNull { profile -> val users = profiles.mapNotNull { profile ->
val config = app.config.getFor(profile.id)
val user = ServerSyncRequest.User( val user = ServerSyncRequest.User(
profile.userCode, profile.userCode,
profile.studentNameLong, profile.studentNameLong,
@ -207,9 +206,9 @@ class SzkolnyApi(val app: App) : CoroutineScope {
teams.filter { it.profileId == profile.id }.map { it.code } teams.filter { it.profileId == profile.id }.map { it.code }
) )
val hash = user.toString().md5() val hash = user.toString().md5()
if (hash == config.hash) if (hash == profile.config.hash)
return@mapNotNull null return@mapNotNull null
return@mapNotNull user to config return@mapNotNull user to profile.config
} }
val response = api.serverSync(ServerSyncRequest( val response = api.serverSync(ServerSyncRequest(
@ -258,12 +257,10 @@ class SzkolnyApi(val app: App) : CoroutineScope {
seen = profile.empty seen = profile.empty
notified = profile.empty notified = profile.empty
if (profile.userCode == event.sharedBy) { sharedBy = if (profile.userCode == event.sharedBy)
sharedBy = "self" "self"
addedManually = true else
} else { eventSharedBy
sharedBy = eventSharedBy
}
} }
} }
} }
@ -327,11 +324,14 @@ class SzkolnyApi(val app: App) : CoroutineScope {
} }
@Throws(Exception::class) @Throws(Exception::class)
fun shareNote(note: Note) { fun shareNote(note: Note, teamId: Long? = null) {
val profile = app.db.profileDao().getByIdNow(note.profileId) val profile = app.db.profileDao().getByIdNow(note.profileId)
?: throw NullPointerException("Profile is not found") ?: throw NullPointerException("Profile is not found")
val team = app.db.teamDao().getClassNow(note.profileId) val team = if (teamId == null)
?: throw NullPointerException("TeamClass is not found") 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( val response = api.shareNote(NoteShareRequest(
deviceId = app.deviceId, deviceId = app.deviceId,

View File

@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/ /*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MDCOnsIOWR===.$param2".sha256() return "$param1.MTIzNDU2Nzg5MDHSZrnOj0===.$param2".sha256()
} }
} }

View File

@ -55,7 +55,7 @@ class SzkolnyTask(val app: App, val syncingProfiles: List<Profile>) : IApiTask(-
notificationList notificationList
.mapNotNull { it.profileId } .mapNotNull { it.profileId }
.distinct() .distinct()
.map { app.config.getFor(it).sync.notificationFilter } .map { app.config[it].sync.notificationFilter }
.forEach { filter -> .forEach { filter ->
filter.forEach { type -> filter.forEach { type ->
notificationList.removeAll { it.type == type } notificationList.removeAll { it.type == type }

View File

@ -44,7 +44,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.*
TimetableManual::class, TimetableManual::class,
Note::class, Note::class,
Metadata::class Metadata::class
], version = 99) ], version = 100)
@TypeConverters( @TypeConverters(
ConverterTime::class, ConverterTime::class,
ConverterDate::class, ConverterDate::class,
@ -188,6 +188,7 @@ abstract class AppDb : RoomDatabase() {
Migration97(), Migration97(),
Migration98(), Migration98(),
Migration99(), Migration99(),
Migration100(),
).allowMainThreadQueries().build() ).allowMainThreadQueries().build()
} }
} }

View File

@ -5,13 +5,37 @@
package pl.szczodrzynski.edziennik.data.db.converter package pl.szczodrzynski.edziennik.data.db.converter
import androidx.room.TypeConverter import androidx.room.TypeConverter
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.enums.LoginType
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.*
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
class ConverterEnums { class ConverterEnums {
@TypeConverter @TypeConverter
fun fromEnum(value: Enum<*>?) = value?.toInt() fun fromFeatureType(value: FeatureType?) = value?.id
@TypeConverter
fun fromLoginMethod(value: LoginMethod?) = value?.id
@TypeConverter
fun fromLoginMode(value: LoginMode?) = value?.id
@TypeConverter
fun fromLoginType(value: LoginType?) = value?.id
@TypeConverter
fun fromMetadataType(value: MetadataType?) = value?.id
@TypeConverter
fun fromNotificationType(value: NotificationType?) = value?.id
@TypeConverter
fun fromNavTarget(value: NavTarget?) = value?.id
@TypeConverter @TypeConverter
fun toFeatureType(value: Int?) = value.asFeatureTypeOrNull() fun toFeatureType(value: Int?) = value.asFeatureTypeOrNull()

View File

@ -49,7 +49,7 @@ interface ProfileDao {
@get:Query("SELECT profileId FROM profiles WHERE profileId >= 0 ORDER BY profileId") @get:Query("SELECT profileId FROM profiles WHERE profileId >= 0 ORDER BY profileId")
val idsNow: List<Int> val idsNow: List<Int>
@Query("SELECT profiles.* FROM teams JOIN profiles USING(profileId) WHERE teamCode = :teamCode AND registration = " + Profile.REGISTRATION_ENABLED + " AND enableSharedEvents = 1") @Query("SELECT profiles.* FROM teams JOIN profiles USING(profileId) WHERE teamCode = :teamCode AND registration = " + Profile.REGISTRATION_ENABLED)
fun getByTeamCodeNowWithRegistration(teamCode: String?): List<Profile> fun getByTeamCodeNowWithRegistration(teamCode: String?): List<Profile>
@get:Query("SELECT profileId FROM profiles WHERE profileId > 0 ORDER BY profileId ASC LIMIT 1") @get:Query("SELECT profileId FROM profiles WHERE profileId > 0 ORDER BY profileId ASC LIMIT 1")

View File

@ -107,6 +107,9 @@ abstract class TimetableDao : BaseDao<Lesson, LessonFull> {
fun getByIdNow(profileId: Int, id: Long) = fun getByIdNow(profileId: Int, id: Long) =
getOneNow("$QUERY WHERE timetable.profileId = $profileId AND timetable.id = $id") getOneNow("$QUERY WHERE timetable.profileId = $profileId AND timetable.id = $id")
fun getByOwnerIdNow(profileId: Int, ownerId: Long) =
getOneNow("$QUERY WHERE timetable.profileId = $profileId AND timetable.ownerId = $ownerId")
@Query("UPDATE timetable SET keep = 0 WHERE profileId = :profileId AND isExtra = :isExtra AND type != -1 AND ((type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom))") @Query("UPDATE timetable SET keep = 0 WHERE profileId = :profileId AND isExtra = :isExtra AND type != -1 AND ((type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom))")
abstract fun dontKeepFromDate(profileId: Int, dateFrom: Date, isExtra: Boolean) abstract fun dontKeepFromDate(profileId: Int, dateFrom: Date, isExtra: Boolean)

View File

@ -73,13 +73,22 @@ open class Event(
const val COLOR_INFORMATION = 0xff039be5.toInt() const val COLOR_INFORMATION = 0xff039be5.toInt()
} }
/**
* Added manually - added by self, shared by self, or shared by someone else.
*/
@ColumnInfo(name = "eventAddedManually") @ColumnInfo(name = "eventAddedManually")
var addedManually: Boolean = false var addedManually: Boolean = false
get() = field || sharedBy == "self" get() = field || isShared
/**
* Shared by - user code who shared the event. Null if not shared.
* "Self" if shared by this app user.
*/
@ColumnInfo(name = "eventSharedBy") @ColumnInfo(name = "eventSharedBy")
var sharedBy: String? = null var sharedBy: String? = null
@ColumnInfo(name = "eventSharedByName") @ColumnInfo(name = "eventSharedByName")
var sharedByName: String? = null var sharedByName: String? = null
@ColumnInfo(name = "eventBlacklisted") @ColumnInfo(name = "eventBlacklisted")
var blacklisted: Boolean = false var blacklisted: Boolean = false
@ColumnInfo(name = "eventIsDone") @ColumnInfo(name = "eventIsDone")
@ -104,6 +113,27 @@ open class Event(
var attachmentIds: MutableList<Long>? = null var attachmentIds: MutableList<Long>? = null
var attachmentNames: MutableList<String>? = null var attachmentNames: MutableList<String>? = null
val isHomework
get() = type == TYPE_HOMEWORK
/**
* Whether the event is shared by anyone. Note that this implies [addedManually].
*/
val isShared
get() = sharedBy != null
/**
* Whether the event is shared by "self" (this app user).
*/
val isSharedSent
get() = sharedBy == "self"
/**
* Whether the event is shared by someone else from the class group.
*/
val isSharedReceived
get() = sharedBy != null && sharedBy != "self"
/** /**
* Add an attachment * Add an attachment
* @param id attachment ID * @param id attachment ID
@ -134,9 +164,6 @@ open class Event(
it.timeInMillis += 45 * MINUTE * 1000 it.timeInMillis += 45 * MINUTE * 1000
} }
val isHomework
get() = type == TYPE_HOMEWORK
@Ignore @Ignore
fun withMetadata(metadata: Metadata) = EventFull(this, metadata) fun withMetadata(metadata: Metadata) = EventFull(this, metadata)
} }

View File

@ -50,6 +50,13 @@ open class Lesson(
var isExtra: Boolean = false var isExtra: Boolean = false
/**
* Stable ID denoting this lesson, used for note sharing (i.e. [profileId]-independent).
*
* This is simply the Unix timestamp of the lesson (in seconds).
*/
var ownerId: Long = id
val displayDate: Date? val displayDate: Date?
get() { get() {
if (type == TYPE_SHIFTED_SOURCE) if (type == TYPE_SHIFTED_SOURCE)
@ -69,7 +76,12 @@ open class Lesson(
val isChange val isChange
get() = type == TYPE_CHANGE || type == TYPE_SHIFTED_TARGET get() = type == TYPE_CHANGE || type == TYPE_SHIFTED_TARGET
fun buildId(): Long = (displayDate?.combineWith(displayStartTime) ?: 0L) / 6L * 10L + (hashCode() and 0xFFFF) fun buildId(): Long =
(displayDate?.combineWith(displayStartTime) ?: 0L) / 6L * 10L +
(hashCode() and 0xFFFF)
fun buildOwnerId(): Long =
(displayDate?.combineWith(displayStartTime) ?: 0L)
@Ignore @Ignore
var showAsUnseen = false var showAsUnseen = false

View File

@ -9,6 +9,7 @@ interface Noteable {
fun getNoteType(): Note.OwnerType fun getNoteType(): Note.OwnerType
fun getNoteOwnerProfileId(): Int fun getNoteOwnerProfileId(): Int
fun getNoteOwnerId(): Long fun getNoteOwnerId(): Long
fun getNoteShareTeamId(): Long? = null
var notes: MutableList<Note> var notes: MutableList<Note>

View File

@ -5,25 +5,18 @@
package pl.szczodrzynski.edziennik.data.db.entity package pl.szczodrzynski.edziennik.data.db.entity
import android.content.Context import android.content.Context
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.Drawable
import android.widget.ImageView import android.widget.ImageView
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Ignore import androidx.room.Ignore
import com.google.gson.JsonObject import com.google.gson.JsonObject
import pl.droidsonroids.gif.GifDrawable
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.dateToSemester
import pl.szczodrzynski.edziennik.utils.ProfileImageHolder import pl.szczodrzynski.edziennik.ext.getDrawable
import pl.szczodrzynski.edziennik.ext.getHolder
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.ImageHolder
import pl.szczodrzynski.navlib.R
import pl.szczodrzynski.navlib.drawer.IDrawerProfile import pl.szczodrzynski.navlib.drawer.IDrawerProfile
import pl.szczodrzynski.navlib.getDrawableFromRes
@Entity(tableName = "profiles", primaryKeys = ["profileId"]) @Entity(tableName = "profiles", primaryKeys = ["profileId"])
open class Profile( open class Profile(
@ -60,9 +53,13 @@ open class Profile(
} }
override var image: String? = null override var image: String? = null
var empty = true var empty = true
var archived = false var archived = false
var syncEnabled = true
@ColumnInfo(name = "enableSharedEvents")
var unused1 = true
var registration = REGISTRATION_UNSPECIFIED
var userCode = ""
/** /**
* A unique ID matching [archived] profiles with current ones * A unique ID matching [archived] profiles with current ones
@ -70,117 +67,35 @@ open class Profile(
*/ */
var archiveId: Int? = null var archiveId: Int? = null
var syncEnabled = true
var enableSharedEvents = true
var registration = REGISTRATION_UNSPECIFIED
var userCode = ""
/** /**
* The student's number in the class register. * The student's number in the class register.
*/ */
var studentNumber = -1 var studentNumber = -1
var studentClassName: String? = null var studentClassName: String? = null
var studentSchoolYearStart = Date.getToday().let { if (it.month < 9) it.year - 1 else it.year } var studentSchoolYearStart = Date.getToday().let { if (it.month < 9) it.year - 1 else it.year }
var dateSemester1Start = Date(studentSchoolYearStart, 9, 1) var dateSemester1Start = Date(studentSchoolYearStart, 9, 1)
var dateSemester2Start = Date(studentSchoolYearStart + 1, 2, 1) var dateSemester2Start = Date(studentSchoolYearStart + 1, 2, 1)
var dateYearEnd = Date(studentSchoolYearStart + 1, 6, 30) var dateYearEnd = Date(studentSchoolYearStart + 1, 6, 30)
fun getSemesterStart(semester: Int) = if (semester == 1) dateSemester1Start else dateSemester2Start
fun getSemesterEnd(semester: Int) = if (semester == 1) dateSemester2Start.clone().stepForward(0, 0, -1) else dateYearEnd
fun dateToSemester(date: Date) = if (date >= dateSemester2Start) 2 else 1
@delegate:Ignore
val currentSemester by lazy { dateToSemester(Date.getToday()) }
fun shouldArchive(): Boolean {
// vulcan hotfix
if (dateYearEnd.month > 6) {
dateYearEnd.month = 6
dateYearEnd.day = 30
}
// fix for when versions <4.3 synced 2020/2021 year dates to older profiles during 2020 Jun-Aug
if (dateSemester1Start.year > studentSchoolYearStart) {
val diff = dateSemester1Start.year - studentSchoolYearStart
dateSemester1Start.year -= diff
dateSemester2Start.year -= diff
dateYearEnd.year -= diff
}
return App.config.archiverEnabled
&& Date.getToday() >= dateYearEnd
&& Date.getToday().year > studentSchoolYearStart
}
fun isBeforeYear() = false && Date.getToday() < dateSemester1Start
var disabledNotifications: List<Long>? = null var disabledNotifications: List<Long>? = null
var lastReceiversSync: Long = 0 var lastReceiversSync: Long = 0
fun hasStudentData(key: String) = studentData.has(key) val currentSemester
fun getStudentData(key: String, defaultValue: Boolean) = studentData.getBoolean(key) ?: defaultValue get() = dateToSemester(Date.getToday())
fun getStudentData(key: String, defaultValue: String?) = studentData.getString(key) ?: defaultValue
fun getStudentData(key: String, defaultValue: Int) = studentData.getInt(key) ?: defaultValue
fun getStudentData(key: String, defaultValue: Long) = studentData.getLong(key) ?: defaultValue
fun getStudentData(key: String, defaultValue: Float) = studentData.getFloat(key) ?: defaultValue
fun getStudentData(key: String, defaultValue: Char) = studentData.getChar(key) ?: defaultValue
fun putStudentData(key: String, value: Boolean) { studentData[key] = value }
fun putStudentData(key: String, value: String?) { studentData[key] = value }
fun putStudentData(key: String, value: Number) { studentData[key] = value }
fun putStudentData(key: String, value: Char) { studentData[key] = value }
fun removeStudentData(key: String) { studentData.remove(key) }
val isParent val isParent
get() = accountName != null get() = accountName != null
val accountOwnerName val accountOwnerName
get() = accountName ?: studentNameLong get() = accountName ?: studentNameLong
val registerName
@Ignore get() = loginStoreType.name.lowercase()
val registerName = loginStoreType.name.lowercase()
val canShare val canShare
get() = registration == REGISTRATION_ENABLED && !archived get() = registration == REGISTRATION_ENABLED && !archived
override fun getImageDrawable(context: Context): Drawable { @delegate:Ignore
if (archived) { @delegate:Transient
return context.getDrawableFromRes(pl.szczodrzynski.edziennik.R.drawable.profile_archived).also { val config by lazy { App.config[this.id] }
it.colorFilter = PorterDuffColorFilter(colorFromName(name), PorterDuff.Mode.DST_OVER)
}
}
if (!image.isNullOrEmpty()) { override fun getImageDrawable(context: Context) = this.getDrawable(context)
try { override fun getImageHolder(context: Context) = this.getHolder()
return if (image?.endsWith(".gif", true) == true) {
GifDrawable(image ?: "")
} else {
RoundedBitmapDrawableFactory.create(context.resources, image ?: "")
//return Drawable.createFromPath(image ?: "") ?: throw Exception()
}
}
catch (e: Exception) {
e.printStackTrace()
}
}
return context.getDrawableFromRes(R.drawable.profile).also {
it.colorFilter = PorterDuffColorFilter(colorFromName(name), PorterDuff.Mode.DST_OVER)
}
}
override fun getImageHolder(context: Context): ImageHolder {
if (archived) {
return ImageHolder(pl.szczodrzynski.edziennik.R.drawable.profile_archived, colorFromName(name))
}
return if (!image.isNullOrEmpty()) {
try {
ProfileImageHolder(image ?: "")
} catch (_: Exception) {
ImageHolder(R.drawable.profile, colorFromName(name))
}
}
else {
ImageHolder(R.drawable.profile, colorFromName(name))
}
}
override fun applyImageTo(imageView: ImageView) { override fun applyImageTo(imageView: ImageView) {
getImageHolder(imageView.context).applyTo(imageView) getImageHolder(imageView.context).applyTo(imageView)
} }

View File

@ -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.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Note import pl.szczodrzynski.edziennik.data.db.entity.Note
import pl.szczodrzynski.edziennik.data.db.entity.Noteable 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.ui.search.Searchable
import pl.szczodrzynski.edziennik.utils.html.BetterHtml import pl.szczodrzynski.edziennik.utils.html.BetterHtml
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
@ -118,4 +119,5 @@ class EventFull(
override fun getNoteType() = Note.OwnerType.EVENT override fun getNoteType() = Note.OwnerType.EVENT
override fun getNoteOwnerProfileId() = profileId override fun getNoteOwnerProfileId() = profileId
override fun getNoteOwnerId() = id override fun getNoteOwnerId() = id
override fun getNoteShareTeamId() = teamId.takePositive()
} }

View File

@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.db.entity.Note import pl.szczodrzynski.edziennik.data.db.entity.Note
import pl.szczodrzynski.edziennik.data.db.entity.Noteable import pl.szczodrzynski.edziennik.data.db.entity.Noteable
import pl.szczodrzynski.edziennik.ext.takePositive
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
class LessonFull( class LessonFull(
@ -137,9 +138,10 @@ class LessonFull(
var seen: Boolean = false var seen: Boolean = false
var notified: Boolean = false var notified: Boolean = false
@Relation(parentColumn = "id", entityColumn = "noteOwnerId", entity = Note::class) @Relation(parentColumn = "ownerId", entityColumn = "noteOwnerId", entity = Note::class)
override lateinit var notes: MutableList<Note> override lateinit var notes: MutableList<Note>
override fun getNoteType() = Note.OwnerType.LESSON override fun getNoteType() = Note.OwnerType.LESSON
override fun getNoteOwnerProfileId() = profileId override fun getNoteOwnerProfileId() = profileId
override fun getNoteOwnerId() = id override fun getNoteOwnerId() = ownerId
override fun getNoteShareTeamId() = teamId.takePositive()
} }

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) Kuba Szczodrzyński 2022-10-25.
*/
package pl.szczodrzynski.edziennik.data.db.migration
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration100 : Migration(99, 100) {
override fun migrate(database: SupportSQLiteDatabase) {
// add Note Owner ID to Lesson, to make it profileId-independent
// calculate the new owner ID based on the old ID
database.execSQL("ALTER TABLE timetable ADD COLUMN ownerId INT NOT NULL DEFAULT 0;")
// set new ID for actual lessons
database.execSQL("UPDATE timetable SET ownerId = ROUND((id & ~65535) / 500000.0) * 300000;")
// copy the old ID (date value) for NO_LESSONS
database.execSQL("UPDATE timetable SET ownerId = id WHERE type = -1;")
// update ID for notes as well
database.execSQL("UPDATE notes SET noteOwnerId = ROUND((noteOwnerId & ~65535) / 500000.0) * 300000 WHERE noteOwnerType = 'LESSON' AND noteOwnerId > 2000000000000;")
// force full app sync to download notes with new IDs
database.execSQL("DELETE FROM config WHERE `key` = 'hash';")
database.execSQL("DELETE FROM config WHERE `key` = 'lastAppSync';")
}
}

View File

@ -160,11 +160,11 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
if (event.color == -1) if (event.color == -1)
event.color = null event.color = null
event.addedManually = true
event.sharedBy = json.getString("sharedBy") event.sharedBy = json.getString("sharedBy")
event.sharedByName = json.getString("sharedByName") event.sharedByName = json.getString("sharedByName")
if (profile.userCode == event.sharedBy) { if (profile.userCode == event.sharedBy) {
event.sharedBy = "self" event.sharedBy = "self"
event.addedManually = true
} }
val metadata = Metadata( val metadata = Metadata(
@ -176,7 +176,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
) )
val type = if (event.isHomework) NotificationType.SHARED_HOMEWORK else NotificationType.SHARED_EVENT val type = if (event.isHomework) NotificationType.SHARED_HOMEWORK else NotificationType.SHARED_EVENT
val notificationFilter = app.config.getFor(event.profileId).sync.notificationFilter val notificationFilter = app.config[event.profileId].sync.notificationFilter
if (!notificationFilter.contains(type) && event.sharedBy != "self" && event.date >= Date.getToday()) { if (!notificationFilter.contains(type) && event.sharedBy != "self" && event.date >= Date.getToday()) {
val notification = Notification( val notification = Notification(
@ -211,7 +211,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
val profile = profiles.firstOrNull { it.id == team.profileId } ?: return@forEach val profile = profiles.firstOrNull { it.id == team.profileId } ?: return@forEach
if (!profile.canShare) if (!profile.canShare)
return@forEach return@forEach
val notificationFilter = app.config.getFor(team.profileId).sync.notificationFilter val notificationFilter = app.config[team.profileId].sync.notificationFilter
if (!notificationFilter.contains(NotificationType.REMOVED_SHARED_EVENT)) { if (!notificationFilter.contains(NotificationType.REMOVED_SHARED_EVENT)) {
val notification = Notification( val notification = Notification(
@ -265,7 +265,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
return@forEach return@forEach
val type = NotificationType.SHARED_NOTE val type = NotificationType.SHARED_NOTE
val notificationFilter = app.config.getFor(note.profileId).sync.notificationFilter val notificationFilter = app.config[note.profileId].sync.notificationFilter
if (!notificationFilter.contains(type) && note.sharedBy != "self") { if (!notificationFilter.contains(type) && note.sharedBy != "self") {
val notification = Notification( val notification = Notification(

View File

@ -6,12 +6,37 @@ package pl.szczodrzynski.edziennik.data.firebase
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ANNOUNCEMENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ATTENDANCES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_CATEGORIES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADE_COMMENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_EVENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_HOMEWORK
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_LUCKY_NUMBER
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_CATEGORIES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NOTICES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_POINT_GRADES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_PT_MEETINGS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEXT_GRADES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TIMETABLES
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_MESSAGES_RECEIVED
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
import pl.szczodrzynski.edziennik.data.api.task.IApiTask import pl.szczodrzynski.edziennik.data.api.task.IApiTask
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.getString
import pl.szczodrzynski.edziennik.ext.getStudentData
class SzkolnyLibrusFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) { class SzkolnyLibrusFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) {
/*{ /*{

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.getLong import pl.szczodrzynski.edziennik.ext.getLong
import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.getString
import pl.szczodrzynski.edziennik.ext.getStudentData
class SzkolnyMobidziennikFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) { class SzkolnyMobidziennikFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) {
/*{ /*{

View File

@ -4,15 +4,15 @@
package pl.szczodrzynski.edziennik.data.firebase package pl.szczodrzynski.edziennik.data.firebase
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.task.IApiTask 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.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.getInt import pl.szczodrzynski.edziennik.ext.getInt
import pl.szczodrzynski.edziennik.ext.getString import pl.szczodrzynski.edziennik.ext.getString
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.toJsonObject import pl.szczodrzynski.edziennik.ext.toJsonObject
class SzkolnyVulcanFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) { class SzkolnyVulcanFirebase(val app: App, val profiles: List<Profile>, val message: FirebaseService.Message) {

View File

@ -6,14 +6,9 @@ package pl.szczodrzynski.edziennik.ext
import android.util.LongSparseArray import android.util.LongSparseArray
import androidx.core.util.forEach import androidx.core.util.forEach
import com.google.android.material.datepicker.CalendarConstraints
import com.google.gson.JsonElement
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.entity.Team import pl.szczodrzynski.edziennik.data.db.entity.Team
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
fun List<Teacher>.byId(id: Long) = firstOrNull { it.id == id } fun List<Teacher>.byId(id: Long) = firstOrNull { it.id == id }
fun List<Teacher>.byNameFirstLast(nameFirstLast: String) = firstOrNull { it.name + " " + it.surname == nameFirstLast } fun List<Teacher>.byNameFirstLast(nameFirstLast: String) = firstOrNull { it.name + " " + it.surname == nameFirstLast }
@ -34,22 +29,3 @@ fun LongSparseArray<Team>.getById(id: Long): Team? {
} }
return null return null
} }
operator fun Profile.set(key: String, value: JsonElement) = this.studentData.add(key, value)
operator fun Profile.set(key: String, value: Boolean) = this.studentData.addProperty(key, value)
operator fun Profile.set(key: String, value: String?) = this.studentData.addProperty(key, value)
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 Profile.getSchoolYearConstrains(): CalendarConstraints {
return CalendarConstraints.Builder()
.setStart(dateSemester1Start.inMillisUtc)
.setEnd(dateYearEnd.inMillisUtc)
.build()
}
fun Profile.hasFeature(featureType: FeatureType) = featureType in this.loginStoreType.features
fun Profile.hasUIFeature(featureType: FeatureType) = featureType.isUIAlwaysAvailable || hasFeature(featureType)
fun Profile.getAppData() =
if (App.profileId == this.id) App.data else AppData.get(this.loginStoreType)

View File

@ -76,6 +76,9 @@ fun pendingIntentFlag(): Int {
fun Int?.takeValue() = if (this == -1) null else this fun Int?.takeValue() = if (this == -1) null else this
fun Int?.takePositive() = if (this == -1 || this == 0) 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 String?.takeValue() = if (this.isNullOrBlank()) null else this
fun Any?.ignore() = Unit fun Any?.ignore() = Unit

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) Kuba Szczodrzyński 2022-10-25.
*/
package pl.szczodrzynski.edziennik.ext
import android.content.Context
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.Drawable
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import com.google.android.material.datepicker.CalendarConstraints
import com.google.gson.JsonElement
import pl.droidsonroids.gif.GifDrawable
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.utils.ProfileImageHolder
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.ImageHolder
import pl.szczodrzynski.navlib.getDrawableFromRes
// TODO refactor Data* fields and make the receiver non-nullable
operator fun Profile?.set(key: String, value: JsonElement) = this?.studentData?.add(key, value)
operator fun Profile?.set(key: String, value: Boolean) = this?.studentData?.addProperty(key, value)
operator fun Profile?.set(key: String, value: String?) = this?.studentData?.addProperty(key, value)
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 Profile.getStudentData(key: String, defaultValue: Boolean) =
studentData.getBoolean(key) ?: defaultValue
fun Profile.getStudentData(key: String, defaultValue: String?) =
studentData.getString(key) ?: defaultValue
fun Profile.getStudentData(key: String, defaultValue: Int) =
studentData.getInt(key) ?: defaultValue
fun Profile.getStudentData(key: String, defaultValue: Long) =
studentData.getLong(key) ?: defaultValue
fun Profile.getStudentData(key: String, defaultValue: Float) =
studentData.getFloat(key) ?: defaultValue
fun Profile.getStudentData(key: String, defaultValue: Char) =
studentData.getChar(key) ?: defaultValue
fun Profile.getSemesterStart(semester: Int) =
if (semester == 1) dateSemester1Start else dateSemester2Start
fun Profile.getSemesterEnd(semester: Int) =
if (semester == 1) dateSemester2Start.clone().stepForward(0, 0, -1) else dateYearEnd
fun Profile.dateToSemester(date: Date) = if (date >= dateSemester2Start) 2 else 1
fun Profile.isBeforeYear() = false && Date.getToday() < dateSemester1Start
fun Profile.getSchoolYearConstrains(): CalendarConstraints {
return CalendarConstraints.Builder()
.setStart(dateSemester1Start.inMillisUtc)
.setEnd(dateYearEnd.inMillisUtc)
.build()
}
fun Profile.hasFeature(featureType: FeatureType) = featureType in this.loginStoreType.features
fun Profile.hasUIFeature(featureType: FeatureType) =
featureType.isUIAlwaysAvailable || hasFeature(featureType)
fun Profile.getAppData() =
if (App.profileId == this.id) App.data else AppData.get(this.loginStoreType)
fun Profile.shouldArchive(): Boolean {
// vulcan hotfix
if (dateYearEnd.month > 6) {
dateYearEnd.month = 6
dateYearEnd.day = 30
}
// fix for when versions <4.3 synced 2020/2021 year dates to older profiles during 2020 Jun-Aug
if (dateSemester1Start.year > studentSchoolYearStart) {
val diff = dateSemester1Start.year - studentSchoolYearStart
dateSemester1Start.year -= diff
dateSemester2Start.year -= diff
dateYearEnd.year -= diff
}
return App.config.archiverEnabled && Date.getToday() >= dateYearEnd && Date.getToday().year > studentSchoolYearStart
}
fun Profile.getDrawable(context: Context): Drawable {
if (archived) {
return context.getDrawableFromRes(R.drawable.profile_archived).also {
it.colorFilter = PorterDuffColorFilter(colorFromName(name), PorterDuff.Mode.DST_OVER)
}
}
if (!image.isNullOrEmpty()) {
try {
return if (image?.endsWith(".gif", true) == true) {
GifDrawable(image ?: "")
} else {
RoundedBitmapDrawableFactory.create(context.resources, image ?: "")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
return context.getDrawableFromRes(R.drawable.profile).also {
it.colorFilter = PorterDuffColorFilter(colorFromName(name), PorterDuff.Mode.DST_OVER)
}
}
fun Profile.getHolder(): ImageHolder {
if (archived) {
return ImageHolder(R.drawable.profile_archived, colorFromName(name))
}
return if (!image.isNullOrEmpty()) {
try {
ProfileImageHolder(image ?: "")
} catch (_: Exception) {
ImageHolder(R.drawable.profile, colorFromName(name))
}
} else {
ImageHolder(R.drawable.profile, colorFromName(name))
}
}

View File

@ -17,7 +17,12 @@ import com.mikepenz.iconics.typeface.library.community.material.CommunityMateria
import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.iconics.utils.sizeDp
import eu.szkolny.font.SzkolnyFont import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
@ -53,7 +58,7 @@ class AgendaFragment : Fragment(), CoroutineScope {
if (getActivity() == null || context == null) return null if (getActivity() == null || context == null) return null
activity = getActivity() as MainActivity activity = getActivity() as MainActivity
context?.theme?.applyStyle(Themes.appTheme, true) context?.theme?.applyStyle(Themes.appTheme, true)
type = app.config.forProfile().ui.agendaViewType type = app.profile.config.ui.agendaViewType
b = when (type) { b = when (type) {
Profile.AGENDA_DEFAULT -> FragmentAgendaDefaultBinding.inflate(inflater, container, false) Profile.AGENDA_DEFAULT -> FragmentAgendaDefaultBinding.inflate(inflater, container, false)
Profile.AGENDA_CALENDAR -> FragmentAgendaCalendarBinding.inflate(inflater, container, false) Profile.AGENDA_CALENDAR -> FragmentAgendaCalendarBinding.inflate(inflater, container, false)
@ -92,7 +97,7 @@ class AgendaFragment : Fragment(), CoroutineScope {
activity.bottomSheet.close() activity.bottomSheet.close()
type = type =
if (type == Profile.AGENDA_DEFAULT) Profile.AGENDA_CALENDAR else Profile.AGENDA_DEFAULT if (type == Profile.AGENDA_DEFAULT) Profile.AGENDA_CALENDAR else Profile.AGENDA_DEFAULT
app.config.forProfile().ui.agendaViewType = type app.profile.config.ui.agendaViewType = type
activity.reloadTarget() activity.reloadTarget()
}, },
BottomSheetSeparatorItem(true), BottomSheetSeparatorItem(true),

View File

@ -16,7 +16,12 @@ import com.github.tibolte.agendacalendarview.agenda.AgendaAdapter
import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent
import com.github.tibolte.agendacalendarview.models.CalendarEvent import com.github.tibolte.agendacalendarview.models.CalendarEvent
import com.github.tibolte.agendacalendarview.models.IDayItem import com.github.tibolte.agendacalendarview.models.IDayItem
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
@ -49,7 +54,6 @@ class AgendaFragmentDefault(
private val unreadDates = mutableSetOf<Int>() private val unreadDates = mutableSetOf<Int>()
private val events = mutableListOf<CalendarEvent>() private val events = mutableListOf<CalendarEvent>()
private var isInitialized = false private var isInitialized = false
private val profileConfig by lazy { app.config.forProfile().ui }
private val listView private val listView
get() = b.agendaDefaultView.agendaView.agendaListView get() = b.agendaDefaultView.agendaView.agendaListView
@ -107,10 +111,10 @@ class AgendaFragmentDefault(
isInitialized = false isInitialized = false
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
if (profileConfig.agendaLessonChanges) if (app.profile.config.ui.agendaLessonChanges)
addLessonChanges(events) addLessonChanges(events)
if (profileConfig.agendaTeacherAbsence) if (app.profile.config.ui.agendaTeacherAbsence)
addTeacherAbsence(events) addTeacherAbsence(events)
} }
@ -127,7 +131,7 @@ class AgendaFragmentDefault(
val dateStart = app.profile.dateSemester1Start.asCalendar val dateStart = app.profile.dateSemester1Start.asCalendar
val dateEnd = app.profile.dateYearEnd.asCalendar val dateEnd = app.profile.dateYearEnd.asCalendar
val isCompactMode = profileConfig.agendaCompactMode val isCompactMode = app.profile.config.ui.agendaCompactMode
b.agendaDefaultView.init( b.agendaDefaultView.init(
events, events,
@ -247,7 +251,7 @@ class AgendaFragmentDefault(
) { ) {
events.removeAll { it is AgendaEvent || it is AgendaEventGroup } events.removeAll { it is AgendaEvent || it is AgendaEventGroup }
if (!profileConfig.agendaGroupByType) { if (!app.profile.config.ui.agendaGroupByType) {
events += eventList.map { events += eventList.map {
if (!it.seen) if (!it.seen)
unreadDates.add(it.date.value) unreadDates.add(it.date.value)

View File

@ -18,7 +18,6 @@ import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R 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.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.databinding.AttendanceFragmentBinding import pl.szczodrzynski.edziennik.databinding.AttendanceFragmentBinding
import pl.szczodrzynski.edziennik.ext.Bundle import pl.szczodrzynski.edziennik.ext.Bundle
@ -83,7 +82,7 @@ class AttendanceFragment : Fragment(), CoroutineScope {
activity.gainAttention() activity.gainAttention()
if (pageSelection == 1) if (pageSelection == 1)
pageSelection = app.config.forProfile().attendance.attendancePageSelection pageSelection = app.profile.config.attendance.attendancePageSelection
val pagerAdapter = FragmentLazyPagerAdapter( val pagerAdapter = FragmentLazyPagerAdapter(
parentFragmentManager, parentFragmentManager,
@ -114,7 +113,7 @@ class AttendanceFragment : Fragment(), CoroutineScope {
currentItem = pageSelection currentItem = pageSelection
addOnPageSelectedListener { addOnPageSelectedListener {
pageSelection = it pageSelection = it
app.config.forProfile().attendance.attendancePageSelection = it app.profile.config.attendance.attendancePageSelection = it
} }
b.tabLayout.setupWithViewPager(this) b.tabLayout.setupWithViewPager(this)
} }

View File

@ -129,8 +129,8 @@ class AttendanceListFragment : LazyFragment(), CoroutineScope {
if (attendance.isEmpty()) if (attendance.isEmpty())
return mutableListOf() return mutableListOf()
val groupConsecutiveDays = app.config.forProfile().attendance.groupConsecutiveDays val groupConsecutiveDays = app.profile.config.attendance.groupConsecutiveDays
val showPresenceInMonth = app.config.forProfile().attendance.showPresenceInMonth val showPresenceInMonth = app.profile.config.attendance.showPresenceInMonth
if (viewType == AttendanceFragment.VIEW_DAYS) { if (viewType == AttendanceFragment.VIEW_DAYS) {
val items = attendance val items = attendance

View File

@ -62,6 +62,7 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
b.last10unseen.isVisible = false b.last10unseen.isVisible = false
b.fullSync.isVisible = false b.fullSync.isVisible = false
b.clearProfile.isVisible = false b.clearProfile.isVisible = false
b.clearEndpointTimers.isVisible = false
b.rodo.isVisible = false b.rodo.isVisible = false
b.removeHomework.isVisible = false b.removeHomework.isVisible = false
b.unarchive.isVisible = false b.unarchive.isVisible = false
@ -82,15 +83,19 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
app.db.teacherDao().query(SimpleSQLiteQuery("UPDATE teachers SET teacherSurname = \"\" WHERE profileId = ${App.profileId}")) app.db.teacherDao().query(SimpleSQLiteQuery("UPDATE teachers SET teacherSurname = \"\" WHERE profileId = ${App.profileId}"))
} }
b.fullSync.onClick { b.fullSync.onClick {
app.db.query(SimpleSQLiteQuery("UPDATE profiles SET empty = 1 WHERE profileId = ${App.profileId}")) app.profile.empty = true
app.db.query(SimpleSQLiteQuery("DELETE FROM endpointTimers WHERE profileId = ${App.profileId}")) app.profileSave()
} }
b.clearProfile.onClick { b.clearProfile.onClick {
ProfileRemoveDialog(activity, App.profileId, "FAKE", noProfileRemoval = true).show() ProfileRemoveDialog(activity, App.profileId, "FAKE", noProfileRemoval = true).show()
} }
b.clearEndpointTimers.onClick {
app.db.endpointTimerDao().clear(app.profileId)
}
b.removeHomework.onClick { b.removeHomework.onClick {
app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}") app.db.eventDao().getRawNow("UPDATE events SET homeworkBody = NULL WHERE profileId = ${App.profileId}")
} }

View File

@ -12,11 +12,16 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.gson.* import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.JsonPrimitive
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.databinding.TemplateListPageFragmentBinding import pl.szczodrzynski.edziennik.databinding.TemplateListPageFragmentBinding
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.*
@ -66,7 +71,7 @@ class LabProfileFragment : LazyFragment(), CoroutineScope {
"LoginStore" -> loginStore "LoginStore" -> loginStore
"LoginStore / data" -> loginStore?.data ?: JsonObject() "LoginStore / data" -> loginStore?.data ?: JsonObject()
"Config" -> app.config.values "Config" -> app.config.values
"Config (profile)" -> app.config.forProfile().values "Config (profile)" -> app.profile.config.values
else -> when (obj) { else -> when (obj) {
is JsonObject -> (obj as JsonObject).get(el) is JsonObject -> (obj as JsonObject).get(el)
is JsonArray -> (obj as JsonArray).get(el.toInt()) is JsonArray -> (obj as JsonArray).get(el.toInt())
@ -176,7 +181,7 @@ class LabProfileFragment : LazyFragment(), CoroutineScope {
json.add("LoginStore", app.gson.toJsonTree(loginStore)) json.add("LoginStore", app.gson.toJsonTree(loginStore))
json.add("LoginStore / data", loginStore?.data ?: JsonObject()) json.add("LoginStore / data", loginStore?.data ?: JsonObject())
json.add("Config", JsonParser.parseString(app.gson.toJson(app.config.values.toSortedMap()))) 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()))) json.add("Config (profile)", JsonParser.parseString(app.gson.toJson(app.profile.config.values.toSortedMap())))
} }
adapter.items = LabJsonAdapter.expand(json, 0) adapter.items = LabJsonAdapter.expand(json, 0)
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()

View File

@ -6,13 +6,11 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.databinding.DialogConfigAgendaBinding import pl.szczodrzynski.edziennik.databinding.DialogConfigAgendaBinding
import pl.szczodrzynski.edziennik.ext.onChange import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ui.dialogs.base.ConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.base.ConfigDialog
import java.util.*
class AgendaConfigDialog( class AgendaConfigDialog(
activity: AppCompatActivity, activity: AppCompatActivity,
@ -32,48 +30,35 @@ class AgendaConfigDialog(
override fun inflate(layoutInflater: LayoutInflater) = override fun inflate(layoutInflater: LayoutInflater) =
DialogConfigAgendaBinding.inflate(layoutInflater) DialogConfigAgendaBinding.inflate(layoutInflater)
private val profileConfig by lazy { app.config.forProfile().ui }
override suspend fun loadConfig() { override suspend fun loadConfig() {
b.config = profileConfig b.config = app.profile.config
b.isAgendaMode = profileConfig.agendaViewType == Profile.AGENDA_DEFAULT b.isAgendaMode = app.profile.config.ui.agendaViewType == Profile.AGENDA_DEFAULT
b.eventSharingEnabled.isChecked = var calledFromListener = false
app.profile.enableSharedEvents && app.profile.canShare b.eventSharingEnabled.isChecked = app.profile.canShare
b.shareByDefault.isEnabled = app.profile.canShare
b.eventSharingEnabled.onChange { _, isChecked -> b.eventSharingEnabled.onChange { _, isChecked ->
if (isChecked && !app.profile.canShare) { if (calledFromListener) {
b.eventSharingEnabled.isChecked = false calledFromListener = false
val dialog = RegistrationConfigDialog(
activity,
app.profile,
onChangeListener = { enabled ->
b.eventSharingEnabled.isChecked = enabled
setEventSharingEnabled(enabled)
},
onShowListener,
onDismissListener,
)
dialog.showEnableDialog()
return@onChange return@onChange
} }
setEventSharingEnabled(isChecked) b.eventSharingEnabled.isChecked = !isChecked
val dialog = RegistrationConfigDialog(
activity,
app.profile,
onChangeListener = { enabled ->
calledFromListener = true
b.eventSharingEnabled.isChecked = enabled
b.shareByDefault.isEnabled = enabled
},
onShowListener,
onDismissListener,
)
if (isChecked)
dialog.showEnableDialog()
else
dialog.showDisableDialog()
return@onChange
} }
} }
private fun setEventSharingEnabled(enabled: Boolean) {
if (enabled == app.profile.enableSharedEvents)
return
app.profile.enableSharedEvents = enabled
app.profileSave()
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.event_sharing)
.setMessage(
if (enabled)
R.string.settings_register_shared_events_dialog_enabled_text
else
R.string.settings_register_shared_events_dialog_disabled_text
)
.setPositiveButton(R.string.ok, null)
.show()
}
} }

View File

@ -29,23 +29,21 @@ class AttendanceConfigDialog(
override fun inflate(layoutInflater: LayoutInflater) = override fun inflate(layoutInflater: LayoutInflater) =
AttendanceConfigDialogBinding.inflate(layoutInflater) AttendanceConfigDialogBinding.inflate(layoutInflater)
private val profileConfig by lazy { app.config.getFor(app.profileId).attendance }
override suspend fun loadConfig() { override suspend fun loadConfig() {
b.useSymbols.isChecked = profileConfig.useSymbols b.useSymbols.isChecked = app.profile.config.attendance.useSymbols
b.groupConsecutiveDays.isChecked = profileConfig.groupConsecutiveDays b.groupConsecutiveDays.isChecked = app.profile.config.attendance.groupConsecutiveDays
b.showPresenceInMonth.isChecked = profileConfig.showPresenceInMonth b.showPresenceInMonth.isChecked = app.profile.config.attendance.showPresenceInMonth
} }
override fun initView() { override fun initView() {
b.useSymbols.onChange { _, isChecked -> b.useSymbols.onChange { _, isChecked ->
profileConfig.useSymbols = isChecked app.profile.config.attendance.useSymbols = isChecked
} }
b.groupConsecutiveDays.onChange { _, isChecked -> b.groupConsecutiveDays.onChange { _, isChecked ->
profileConfig.groupConsecutiveDays = isChecked app.profile.config.attendance.groupConsecutiveDays = isChecked
} }
b.showPresenceInMonth.onChange { _, isChecked -> b.showPresenceInMonth.onChange { _, isChecked ->
profileConfig.showPresenceInMonth = isChecked app.profile.config.attendance.showPresenceInMonth = isChecked
} }
} }
} }

View File

@ -45,17 +45,15 @@ class GradesConfigDialog(
override fun inflate(layoutInflater: LayoutInflater) = override fun inflate(layoutInflater: LayoutInflater) =
DialogConfigGradesBinding.inflate(layoutInflater) DialogConfigGradesBinding.inflate(layoutInflater)
private val profileConfig by lazy { app.config.getFor(app.profileId).grades }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override suspend fun loadConfig() { override suspend fun loadConfig() {
b.customPlusCheckBox.isChecked = profileConfig.plusValue != null b.customPlusCheckBox.isChecked = app.profile.config.grades.plusValue != null
b.customPlusValue.isVisible = b.customPlusCheckBox.isChecked b.customPlusValue.isVisible = b.customPlusCheckBox.isChecked
b.customMinusCheckBox.isChecked = profileConfig.minusValue != null b.customMinusCheckBox.isChecked = app.profile.config.grades.minusValue != null
b.customMinusValue.isVisible = b.customMinusCheckBox.isChecked b.customMinusValue.isVisible = b.customMinusCheckBox.isChecked
b.customPlusValue.progress = profileConfig.plusValue ?: 0.5f b.customPlusValue.progress = app.profile.config.grades.plusValue ?: 0.5f
b.customMinusValue.progress = profileConfig.minusValue ?: 0.25f b.customMinusValue.progress = app.profile.config.grades.minusValue ?: 0.25f
when (config.orderBy) { when (config.orderBy) {
ORDER_BY_DATE_DESC -> b.sortGradesByDateRadio ORDER_BY_DATE_DESC -> b.sortGradesByDateRadio
@ -63,13 +61,13 @@ class GradesConfigDialog(
else -> null else -> null
}?.isChecked = true }?.isChecked = true
when (profileConfig.colorMode) { when (app.profile.config.grades.colorMode) {
COLOR_MODE_DEFAULT -> b.gradeColorFromERegister COLOR_MODE_DEFAULT -> b.gradeColorFromERegister
COLOR_MODE_WEIGHTED -> b.gradeColorByValue COLOR_MODE_WEIGHTED -> b.gradeColorByValue
else -> null else -> null
}?.isChecked = true }?.isChecked = true
when (profileConfig.yearAverageMode) { when (app.profile.config.grades.yearAverageMode) {
YEAR_ALL_GRADES -> b.gradeAverageMode4 YEAR_ALL_GRADES -> b.gradeAverageMode4
YEAR_1_AVG_2_AVG -> b.gradeAverageMode0 YEAR_1_AVG_2_AVG -> b.gradeAverageMode0
YEAR_1_SEM_2_AVG -> b.gradeAverageMode1 YEAR_1_SEM_2_AVG -> b.gradeAverageMode1
@ -79,21 +77,21 @@ class GradesConfigDialog(
}?.isChecked = true }?.isChecked = true
b.dontCountGrades.isChecked = b.dontCountGrades.isChecked =
profileConfig.dontCountEnabled && profileConfig.dontCountGrades.isNotEmpty() app.profile.config.grades.dontCountEnabled && app.profile.config.grades.dontCountGrades.isNotEmpty()
b.hideImproved.isChecked = profileConfig.hideImproved b.hideImproved.isChecked = app.profile.config.grades.hideImproved
b.averageWithoutWeight.isChecked = profileConfig.averageWithoutWeight b.averageWithoutWeight.isChecked = app.profile.config.grades.averageWithoutWeight
if (profileConfig.dontCountGrades.isEmpty()) { if (app.profile.config.grades.dontCountGrades.isEmpty()) {
b.dontCountGradesText.setText("nb, 0, bz, bd") b.dontCountGradesText.setText("nb, 0, bz, bd")
} else { } else {
b.dontCountGradesText.setText(profileConfig.dontCountGrades.join(", ")) b.dontCountGradesText.setText(app.profile.config.grades.dontCountGrades.join(", "))
} }
} }
override suspend fun saveConfig() { override suspend fun saveConfig() {
profileConfig.plusValue = app.profile.config.grades.plusValue =
if (b.customPlusCheckBox.isChecked) b.customPlusValue.progress else null if (b.customPlusCheckBox.isChecked) b.customPlusValue.progress else null
profileConfig.minusValue = app.profile.config.grades.minusValue =
if (b.customMinusCheckBox.isChecked) b.customMinusValue.progress else null if (b.customMinusCheckBox.isChecked) b.customMinusValue.progress else null
b.dontCountGradesText.setText( b.dontCountGradesText.setText(
@ -103,8 +101,8 @@ class GradesConfigDialog(
?.lowercase() ?.lowercase()
?.replace(", ", ",") ?.replace(", ", ",")
) )
profileConfig.dontCountEnabled = b.dontCountGrades.isChecked app.profile.config.grades.dontCountEnabled = b.dontCountGrades.isChecked
profileConfig.dontCountGrades = b.dontCountGradesText.text app.profile.config.grades.dontCountGrades = b.dontCountGradesText.text
?.split(",") ?.split(",")
?.map { it.trim() } ?.map { it.trim() }
?: listOf() ?: listOf()
@ -121,39 +119,39 @@ class GradesConfigDialog(
// who the hell named those methods // who the hell named those methods
// THIS SHIT DOES NOT EVEN WORK // THIS SHIT DOES NOT EVEN WORK
b.customPlusValue.doOnStopTrackingTouch { b.customPlusValue.doOnStopTrackingTouch {
profileConfig.plusValue = it.progress app.profile.config.grades.plusValue = it.progress
} }
b.customMinusValue.doOnStopTrackingTouch { b.customMinusValue.doOnStopTrackingTouch {
profileConfig.minusValue = it.progress app.profile.config.grades.minusValue = it.progress
} }
b.sortGradesByDateRadio.setOnSelectedListener { config.orderBy = ORDER_BY_DATE_DESC } b.sortGradesByDateRadio.setOnSelectedListener { config.orderBy = ORDER_BY_DATE_DESC }
b.sortGradesBySubjectRadio.setOnSelectedListener { config.orderBy = ORDER_BY_SUBJECT_ASC } b.sortGradesBySubjectRadio.setOnSelectedListener { config.orderBy = ORDER_BY_SUBJECT_ASC }
b.gradeColorFromERegister.setOnSelectedListener { b.gradeColorFromERegister.setOnSelectedListener {
profileConfig.colorMode = COLOR_MODE_DEFAULT app.profile.config.grades.colorMode = COLOR_MODE_DEFAULT
} }
b.gradeColorByValue.setOnSelectedListener { profileConfig.colorMode = COLOR_MODE_WEIGHTED } b.gradeColorByValue.setOnSelectedListener { app.profile.config.grades.colorMode = COLOR_MODE_WEIGHTED }
b.gradeAverageMode4.setOnSelectedListener { b.gradeAverageMode4.setOnSelectedListener {
profileConfig.yearAverageMode = YEAR_ALL_GRADES app.profile.config.grades.yearAverageMode = YEAR_ALL_GRADES
} }
b.gradeAverageMode0.setOnSelectedListener { b.gradeAverageMode0.setOnSelectedListener {
profileConfig.yearAverageMode = YEAR_1_AVG_2_AVG app.profile.config.grades.yearAverageMode = YEAR_1_AVG_2_AVG
} }
b.gradeAverageMode1.setOnSelectedListener { b.gradeAverageMode1.setOnSelectedListener {
profileConfig.yearAverageMode = YEAR_1_SEM_2_AVG app.profile.config.grades.yearAverageMode = YEAR_1_SEM_2_AVG
} }
b.gradeAverageMode2.setOnSelectedListener { b.gradeAverageMode2.setOnSelectedListener {
profileConfig.yearAverageMode = YEAR_1_AVG_2_SEM app.profile.config.grades.yearAverageMode = YEAR_1_AVG_2_SEM
} }
b.gradeAverageMode3.setOnSelectedListener { b.gradeAverageMode3.setOnSelectedListener {
profileConfig.yearAverageMode = YEAR_1_SEM_2_SEM app.profile.config.grades.yearAverageMode = YEAR_1_SEM_2_SEM
} }
b.hideImproved.onChange { _, isChecked -> profileConfig.hideImproved = isChecked } b.hideImproved.onChange { _, isChecked -> app.profile.config.grades.hideImproved = isChecked }
b.averageWithoutWeight.onChange { _, isChecked -> b.averageWithoutWeight.onChange { _, isChecked ->
profileConfig.averageWithoutWeight = isChecked app.profile.config.grades.averageWithoutWeight = isChecked
} }
b.averageWithoutWeightHelp.onClick { b.averageWithoutWeightHelp.onClick {

View File

@ -28,13 +28,11 @@ class MessagesConfigDialog(
override fun inflate(layoutInflater: LayoutInflater) = override fun inflate(layoutInflater: LayoutInflater) =
MessagesConfigDialogBinding.inflate(layoutInflater) MessagesConfigDialogBinding.inflate(layoutInflater)
private val profileConfig by lazy { app.config.getFor(app.profileId).ui }
override suspend fun loadConfig() { override suspend fun loadConfig() {
b.config = profileConfig b.config = app.profile.config.ui
b.greetingText.setText( b.greetingText.setText(
profileConfig.messagesGreetingText app.profile.config.ui.messagesGreetingText
?: "\n\nZ poważaniem\n${app.profile.accountOwnerName}" ?: "\n\nZ poważaniem\n${app.profile.accountOwnerName}"
) )
} }
@ -42,8 +40,8 @@ class MessagesConfigDialog(
override suspend fun saveConfig() { override suspend fun saveConfig() {
val greetingText = b.greetingText.text?.toString()?.trim() val greetingText = b.greetingText.text?.toString()?.trim()
if (greetingText.isNullOrEmpty()) if (greetingText.isNullOrEmpty())
profileConfig.messagesGreetingText = null app.profile.config.ui.messagesGreetingText = null
else else
profileConfig.messagesGreetingText = "\n\n$greetingText" app.profile.config.ui.messagesGreetingText = "\n\n$greetingText"
} }
} }

View File

@ -30,7 +30,7 @@ class NotificationFilterDialog(
.associateBy { it.titleRes.resolveString(activity) as CharSequence } .associateBy { it.titleRes.resolveString(activity) as CharSequence }
override fun getDefaultSelectedItems() = NotificationType.values() override fun getDefaultSelectedItems() = NotificationType.values()
.filter { it.enabledByDefault != null && it !in app.config.forProfile().sync.notificationFilter } .filter { it.enabledByDefault != null && it !in app.profile.config.sync.notificationFilter }
.toSet() .toSet()
override suspend fun onShow() = Unit override suspend fun onShow() = Unit
@ -47,7 +47,7 @@ class NotificationFilterDialog(
.setTitle(R.string.are_you_sure) .setTitle(R.string.are_you_sure)
.setMessage(R.string.notification_filter_warning) .setMessage(R.string.notification_filter_warning)
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(R.string.ok) { _, _ ->
app.config.forProfile().sync.notificationFilter = disabledTypes app.profile.config.sync.notificationFilter = disabledTypes
dismiss() dismiss()
} }
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
@ -55,7 +55,7 @@ class NotificationFilterDialog(
return NO_DISMISS return NO_DISMISS
} }
app.config.forProfile().sync.notificationFilter = disabledTypes app.profile.config.sync.notificationFilter = disabledTypes
return DISMISS return DISMISS
} }

View File

@ -7,7 +7,11 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
@ -117,7 +121,7 @@ class RegistrationConfigDialog(
profile.registration = Profile.REGISTRATION_ENABLED profile.registration = Profile.REGISTRATION_ENABLED
// force full registration of the user // force full registration of the user
App.config.getFor(profile.id).hash = "" profile.config.hash = ""
SzkolnyApi(app).runCatching(activity) { SzkolnyApi(app).runCatching(activity) {
AppSync(app, mutableListOf(), listOf(profile), this).run( AppSync(app, mutableListOf(), listOf(profile), this).run(

View File

@ -30,14 +30,12 @@ class TimetableConfigDialog(
override fun inflate(layoutInflater: LayoutInflater) = override fun inflate(layoutInflater: LayoutInflater) =
TimetableConfigDialogBinding.inflate(layoutInflater) TimetableConfigDialogBinding.inflate(layoutInflater)
private val profileConfig by lazy { app.config.getFor(app.profileId).ui }
override fun initView() { override fun initView() {
b.features = app.profile.loginStoreType.features b.features = app.profile.loginStoreType.features
} }
override suspend fun loadConfig() { override suspend fun loadConfig() {
b.config = profileConfig b.config = app.profile.config.ui
} }
override suspend fun saveConfig() { override suspend fun saveConfig() {

View File

@ -13,23 +13,33 @@ import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent import pl.szczodrzynski.edziennik.data.api.events.ApiTaskFinishedEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.db.entity.* import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Subject
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.JsonObject
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.onChange
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.RegistrationConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.RegistrationConfigDialog
import pl.szczodrzynski.edziennik.ui.views.TimeDropdown.Companion.DISPLAY_LESSONS import pl.szczodrzynski.edziennik.ui.views.TimeDropdown.Companion.DISPLAY_LESSONS
@ -107,9 +117,6 @@ class EventManualDialog(
} }
override suspend fun onShow() { override suspend fun onShow() {
b.shareSwitch.isChecked = editingShared
b.shareSwitch.isEnabled = !editingShared || (editingShared && editingOwn)
b.showMore.onClick { // TODO iconics is broken b.showMore.onClick { // TODO iconics is broken
it.apply { it.apply {
refreshDrawableState() refreshDrawableState()
@ -137,6 +144,11 @@ class EventManualDialog(
} }
loadLists() loadLists()
val shareByDefault = app.profile.config.shareByDefault && profile.canShare
b.shareSwitch.isChecked = editingShared || editingEvent == null && shareByDefault
b.shareSwitch.isEnabled = !editingShared || editingOwn
} }
private fun updateShareText(checked: Boolean = b.shareSwitch.isChecked) { private fun updateShareText(checked: Boolean = b.shareSwitch.isChecked) {

View File

@ -81,7 +81,7 @@ class GradesListFragment : Fragment(), CoroutineScope {
} }
val items = when { val items = when {
app.config.forProfile().grades.hideSticksFromOld && App.devMode -> grades.filter { it.value != 1.0f } app.profile.config.grades.hideSticksFromOld && App.devMode -> grades.filter { it.value != 1.0f }
else -> grades else -> grades
} }

View File

@ -12,7 +12,9 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.entity.Grade import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.databinding.FragmentGradesEditorBinding import pl.szczodrzynski.edziennik.databinding.FragmentGradesEditorBinding
import pl.szczodrzynski.edziennik.ext.getFloat import pl.szczodrzynski.edziennik.ext.getFloat
@ -37,7 +39,7 @@ class GradesEditorFragment : Fragment() {
private val navController: NavController by lazy { Navigation.findNavController(b.root) } private val navController: NavController by lazy { Navigation.findNavController(b.root) }
*/ */
private val config by lazy { app.config.getFor(App.profileId).grades } private val config by lazy { app.profile.config.grades }
private var subjectId: Long = -1 private var subjectId: Long = -1
private var semester: Int = 1 private var semester: Int = 1

View File

@ -37,18 +37,17 @@ class HomeConfigDialog(
).mapKeys { (resId, _) -> activity.getString(resId) } ).mapKeys { (resId, _) -> activity.getString(resId) }
override fun getDefaultSelectedItems() = override fun getDefaultSelectedItems() =
profileConfig.homeCards app.profile.config.ui.homeCards
.filter { it.profileId == App.profileId } .filter { it.profileId == App.profileId }
.map { it.cardId } .map { it.cardId }
.toSet() .toSet()
override suspend fun onShow() = Unit override suspend fun onShow() = Unit
private val profileConfig by lazy { app.config.getFor(app.profileId).ui }
private var configChanged = false private var configChanged = false
override suspend fun onPositiveClick(): Boolean { override suspend fun onPositiveClick(): Boolean {
val homeCards = profileConfig.homeCards.toMutableList() val homeCards = app.profile.config.ui.homeCards.toMutableList()
homeCards.removeAll { it.profileId == App.profileId } homeCards.removeAll { it.profileId == App.profileId }
homeCards += getMultiSelection().mapNotNull { homeCards += getMultiSelection().mapNotNull {
HomeCardModel( HomeCardModel(
@ -56,7 +55,7 @@ class HomeConfigDialog(
cardId = it as? Int ?: return@mapNotNull null cardId = it as? Int ?: return@mapNotNull null
) )
} }
profileConfig.homeCards = homeCards app.profile.config.ui.homeCards = homeCards
return DISMISS return DISMISS
} }

View File

@ -50,18 +50,18 @@ class HomeFragment : Fragment(), CoroutineScope {
cardAdapter.items[toPosition] = fromCard cardAdapter.items[toPosition] = fromCard
cardAdapter.notifyItemMoved(fromPosition, toPosition) cardAdapter.notifyItemMoved(fromPosition, toPosition)
val homeCards = App.config.forProfile().ui.homeCards.toMutableList() val homeCards = App.profile.config.ui.homeCards.toMutableList()
val fromIndex = homeCards.indexOfFirst { it.cardId == fromCard.id } val fromIndex = homeCards.indexOfFirst { it.cardId == fromCard.id }
val toIndex = homeCards.indexOfFirst { it.cardId == toCard.id } val toIndex = homeCards.indexOfFirst { it.cardId == toCard.id }
val fromPair = homeCards[fromIndex] val fromPair = homeCards[fromIndex]
homeCards[fromIndex] = homeCards[toIndex] homeCards[fromIndex] = homeCards[toIndex]
homeCards[toIndex] = fromPair homeCards[toIndex] = fromPair
App.config.forProfile().ui.homeCards = homeCards App.profile.config.ui.homeCards = homeCards
return true return true
} }
fun removeCard(position: Int, cardAdapter: HomeCardAdapter) { fun removeCard(position: Int, cardAdapter: HomeCardAdapter) {
val homeCards = App.config.forProfile().ui.homeCards.toMutableList() val homeCards = App.profile.config.ui.homeCards.toMutableList()
if (position >= homeCards.size) if (position >= homeCards.size)
return return
val card = cardAdapter.items[position] val card = cardAdapter.items[position]
@ -71,7 +71,7 @@ class HomeFragment : Fragment(), CoroutineScope {
return return
} }
homeCards.removeAll { it.cardId == card.id } homeCards.removeAll { it.cardId == card.id }
App.config.forProfile().ui.homeCards = homeCards App.profile.config.ui.homeCards = homeCards
} }
} }
@ -144,7 +144,7 @@ class HomeFragment : Fragment(), CoroutineScope {
b.refreshLayout.isEnabled = scrollY == 0 b.refreshLayout.isEnabled = scrollY == 0
} }
val cards = app.config.forProfile().ui.homeCards.filter { it.profileId == app.profile.id }.toMutableList() val cards = app.profile.config.ui.homeCards.filter { it.profileId == app.profile.id }.toMutableList()
if (cards.isEmpty()) { if (cards.isEmpty()) {
cards += listOfNotNull( cards += listOfNotNull(
HomeCardModel(app.profile.id, HomeCard.CARD_LUCKY_NUMBER).takeIf { app.profile.hasUIFeature(FeatureType.LUCKY_NUMBER) }, HomeCardModel(app.profile.id, HomeCard.CARD_LUCKY_NUMBER).takeIf { app.profile.hasUIFeature(FeatureType.LUCKY_NUMBER) },
@ -153,7 +153,7 @@ class HomeFragment : Fragment(), CoroutineScope {
HomeCardModel(app.profile.id, HomeCard.CARD_GRADES).takeIf { app.profile.hasUIFeature(FeatureType.GRADES) }, HomeCardModel(app.profile.id, HomeCard.CARD_GRADES).takeIf { app.profile.hasUIFeature(FeatureType.GRADES) },
HomeCardModel(app.profile.id, HomeCard.CARD_NOTES), HomeCardModel(app.profile.id, HomeCard.CARD_NOTES),
) )
app.config.forProfile().ui.homeCards = app.config.forProfile().ui.homeCards.toMutableList().also { it.addAll(cards) } app.profile.config.ui.homeCards = app.profile.config.ui.homeCards.toMutableList().also { it.addAll(cards) }
} }
val items = mutableListOf<HomeCard>() val items = mutableListOf<HomeCard>()

View File

@ -75,6 +75,7 @@ class HomeTimetableCard(
private var counterJob: Job? = null private var counterJob: Job? = null
private var counterStart: Time? = null private var counterStart: Time? = null
private var counterEnd: Time? = null private var counterEnd: Time? = null
private var showAllLessons: Boolean = false
private var subjectSpannable: CharSequence? = null private var subjectSpannable: CharSequence? = null
private val ignoreCancelled = false private val ignoreCancelled = false
@ -276,6 +277,8 @@ class HomeTimetableCard(
counterJob = startCoroutineTimer(repeatMillis = 500) { counterJob = startCoroutineTimer(repeatMillis = 500) {
count() count()
} }
showAllLessons = !isOngoing
} }
else { else {
val isTomorrow = today.clone().stepForward(0, 0, 1) == timetableDate val isTomorrow = today.clone().stepForward(0, 0, 1) == timetableDate
@ -312,12 +315,22 @@ class HomeTimetableCard(
} ?: run { } ?: run {
b.classroom.visibility = View.GONE b.classroom.visibility = View.GONE
} }
showAllLessons = true
} }
val text = mutableListOf<CharSequence>( val text = mutableListOf<CharSequence>(
if (showAllLessons)
activity.getString(R.string.home_timetable_all_lessons)
else
activity.getString(R.string.home_timetable_later) 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) { for (lesson in nextLessons) {
text += listOf( text += listOf(
lesson.displayStartTime?.stringHM, lesson.displayStartTime?.stringHM,
@ -348,6 +361,14 @@ class HomeTimetableCard(
} }
val now = syncedNow 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) { if (now > counterEnd) {
// the lesson is already over // the lesson is already over
b.progress.visibility = View.GONE b.progress.visibility = View.GONE

View File

@ -11,7 +11,11 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.Navigation import androidx.navigation.Navigation
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
@ -73,9 +77,8 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
Profile.REGISTRATION_DISABLED Profile.REGISTRATION_DISABLED
val data = AppData.get(it.loginStoreType) val data = AppData.get(it.loginStoreType)
val config = app.config.getFor(it.id)
for ((key, value) in data.configOverrides) { for ((key, value) in data.configOverrides) {
config.set(key, value) it.config.set(key, value)
} }
app.db.eventTypeDao().addDefaultTypes(it) app.db.eventTypeDao().addDefaultTypes(it)

View File

@ -67,9 +67,8 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
get() = app.messageManager get() = app.messageManager
private val textStylingManager private val textStylingManager
get() = app.textStylingManager get() = app.textStylingManager
private val profileConfig by lazy { app.config.forProfile().ui }
private val greetingText private val greetingText
get() = profileConfig.messagesGreetingText ?: "\n\nZ poważaniem\n${app.profile.accountOwnerName}" get() = app.profile.config.ui.messagesGreetingText ?: "\n\nZ poważaniem\n${app.profile.accountOwnerName}"
private val teachers = mutableListOf<Teacher>() private val teachers = mutableListOf<Teacher>()
@ -242,9 +241,9 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
subject = b.subject, subject = b.subject,
body = b.text, body = b.text,
teachers = teachers, teachers = teachers,
greetingOnCompose = profileConfig.messagesGreetingOnCompose, greetingOnCompose = app.profile.config.ui.messagesGreetingOnCompose,
greetingOnReply = profileConfig.messagesGreetingOnReply, greetingOnReply = app.profile.config.ui.messagesGreetingOnReply,
greetingOnForward = profileConfig.messagesGreetingOnForward, greetingOnForward = app.profile.config.ui.messagesGreetingOnForward,
greetingText = greetingText, greetingText = greetingText,
) )
stylingConfig = StylingConfig( stylingConfig = StylingConfig(

View File

@ -87,7 +87,12 @@ class NoteEditorDialog(
.show() .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() progressDialog?.dismiss()
return success return success
} }
@ -127,8 +132,13 @@ class NoteEditorDialog(
topicStylingConfig = StylingConfigBase(editText = b.topic, htmlMode = HtmlMode.SIMPLE) topicStylingConfig = StylingConfigBase(editText = b.topic, htmlMode = HtmlMode.SIMPLE)
bodyStylingConfig = StylingConfigBase(editText = b.body, htmlMode = HtmlMode.SIMPLE) bodyStylingConfig = StylingConfigBase(editText = b.body, htmlMode = HtmlMode.SIMPLE)
val profile = withContext(Dispatchers.IO) {
app.db.profileDao().getByIdNow(profileId)
}
b.ownerType = owner?.getNoteType() ?: Note.OwnerType.NONE b.ownerType = owner?.getNoteType() ?: Note.OwnerType.NONE
b.editingNote = editingNote b.editingNote = editingNote
b.shareByDefault = app.profile.config.shareByDefault && profile?.canShare == true
b.color.clear().append(Note.Color.values().map { color -> b.color.clear().append(Note.Color.values().map { color ->
TextInputDropDown.Item( TextInputDropDown.Item(

View File

@ -16,13 +16,13 @@ abstract class SettingsCard(
protected val activity: MainActivity = util.activity protected val activity: MainActivity = util.activity
protected val configGlobal by lazy { app.config } protected val configGlobal by lazy { app.config }
protected val configProfile by lazy { app.config.forProfile() } protected val configProfile by lazy { app.profile.config }
val card by lazy { val card by lazy {
buildCard() buildCard()
} }
protected abstract fun buildCard(): MaterialAboutCard protected abstract fun buildCard(): MaterialAboutCard
protected abstract fun getItems(): List<MaterialAboutItem> protected abstract fun getItems(card: MaterialAboutCard): List<MaterialAboutItem>
protected open fun getItemsMore(): List<MaterialAboutItem> = listOf() protected open fun getItemsMore(card: MaterialAboutCard): List<MaterialAboutItem> = listOf()
} }

View File

@ -34,8 +34,8 @@ class SettingsUtil(
fun createCard( fun createCard(
titleRes: Int?, titleRes: Int?,
items: List<MaterialAboutItem>, items: (card: MaterialAboutCard) -> List<MaterialAboutItem>,
itemsMore: List<MaterialAboutItem>, itemsMore: (card: MaterialAboutCard) -> List<MaterialAboutItem>,
backgroundColor: Int? = null, backgroundColor: Int? = null,
theme: Int? = null theme: Int? = null
): MaterialAboutCard { ): MaterialAboutCard {
@ -44,10 +44,11 @@ class SettingsUtil(
.cardColor(backgroundColor ?: 0) .cardColor(backgroundColor ?: 0)
.theme(theme ?: 0) .theme(theme ?: 0)
.build() .build()
card.items.addAll(items) card.items.addAll(items(card))
if (itemsMore.isNotEmpty()) { val more = itemsMore(card)
card.items.add(createMoreItem(card, itemsMore)) if (more.isNotEmpty()) {
card.items.add(createMoreItem(card, more))
} }
return card return card

View File

@ -39,19 +39,13 @@ class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope
MediaPlayer.create(activity, R.raw.ogarnij_sie) MediaPlayer.create(activity, R.raw.ogarnij_sie)
} }
override fun buildCard(): MaterialAboutCard = override fun buildCard() = util.createCard(
util.createCard( null,
null, items = ::getItems,
items = listOf(), itemsMore = ::getItemsMore,
itemsMore = listOf(), backgroundColor = 0xff1976d2.toInt(),
backgroundColor = 0xff1976d2.toInt(), theme = R.style.AppTheme_Dark
theme = R.style.AppTheme_Dark )
).also {
it.items.addAll(getItems(it))
}
override fun getItems() = listOf<MaterialAboutItem>()
override fun getItemsMore() = listOf<MaterialAboutItem>()
private val versionDetailsItem by lazy { private val versionDetailsItem by lazy {
util.createActionItem( util.createActionItem(
@ -64,7 +58,7 @@ class SettingsAboutCard(util: SettingsUtil) : SettingsCard(util), CoroutineScope
) )
} }
private fun getItems(card: MaterialAboutCard) = listOf( override fun getItems(card: MaterialAboutCard) = listOf(
util.createTitleItem(), util.createTitleItem(),
util.createActionItem( util.createActionItem(

View File

@ -5,6 +5,7 @@
package pl.szczodrzynski.edziennik.ui.settings.cards package pl.szczodrzynski.edziennik.ui.settings.cards
import android.content.Intent import android.content.Intent
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileConfigDialog
@ -17,8 +18,8 @@ class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) {
override fun buildCard() = util.createCard( override fun buildCard() = util.createCard(
null, null,
items = getItems(), items = ::getItems,
itemsMore = listOf() itemsMore = ::getItemsMore,
) )
private fun getProfileItem(): MaterialAboutProfileItem = util.createProfileItem( private fun getProfileItem(): MaterialAboutProfileItem = util.createProfileItem(
@ -34,7 +35,7 @@ class SettingsProfileCard(util: SettingsUtil) : SettingsCard(util) {
}).show() }).show()
} }
override fun getItems() = listOf( override fun getItems(card: MaterialAboutCard) = listOf(
getProfileItem(), getProfileItem(),
util.createActionItem( util.createActionItem(

View File

@ -4,7 +4,7 @@
package pl.szczodrzynski.edziennik.ui.settings.cards package pl.szczodrzynski.edziennik.ui.settings.cards
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import eu.szkolny.font.SzkolnyFont import eu.szkolny.font.SzkolnyFont
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
@ -12,8 +12,16 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.ext.after import pl.szczodrzynski.edziennik.ext.after
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.hasUIFeature import pl.szczodrzynski.edziennik.ext.hasUIFeature
import pl.szczodrzynski.edziennik.ui.dialogs.settings.* import pl.szczodrzynski.edziennik.ext.set
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AgendaConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.AttendanceConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.BellSyncConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.MessagesConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.RegistrationConfigDialog
import pl.szczodrzynski.edziennik.ui.dialogs.settings.TimetableConfigDialog
import pl.szczodrzynski.edziennik.ui.settings.SettingsCard import pl.szczodrzynski.edziennik.ui.settings.SettingsCard
import pl.szczodrzynski.edziennik.ui.settings.SettingsUtil import pl.szczodrzynski.edziennik.ui.settings.SettingsUtil
@ -21,8 +29,8 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
override fun buildCard() = util.createCard( override fun buildCard() = util.createCard(
R.string.settings_card_register_title, R.string.settings_card_register_title,
items = getItems(), items = ::getItems,
itemsMore = getItemsMore() itemsMore = ::getItemsMore,
) )
private fun getBellSync() = private fun getBellSync() =
@ -33,29 +41,18 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
) )
} ?: activity.getString(R.string.settings_register_bell_sync_subtext_disabled) } ?: activity.getString(R.string.settings_register_bell_sync_subtext_disabled)
private val sharedEventsItem by lazy { private val sharedEventsDefaultItem by lazy {
util.createPropertyItem( util.createPropertyItem(
text = R.string.settings_register_shared_events_text, text = R.string.settings_register_share_by_default_text,
subText = R.string.settings_register_shared_events_subtext, subText = R.string.settings_register_share_by_default_subtext,
icon = CommunityMaterial.Icon3.cmd_share_outline, icon = CommunityMaterial.Icon3.cmd_toggle_switch_outline,
value = app.profile.enableSharedEvents value = configProfile.shareByDefault
) { _, value -> ) { _, value ->
app.profile.enableSharedEvents = value configProfile.shareByDefault = value
app.profileSave()
MaterialAlertDialogBuilder(activity)
.setTitle(R.string.event_sharing)
.setMessage(
if (value)
R.string.settings_register_shared_events_dialog_enabled_text
else
R.string.settings_register_shared_events_dialog_disabled_text
)
.setPositiveButton(R.string.ok, null)
.show()
} }
} }
override fun getItems() = listOfNotNull( override fun getItems(card: MaterialAboutCard) = listOfNotNull(
util.createActionItem( util.createActionItem(
text = R.string.menu_timetable_config, text = R.string.menu_timetable_config,
icon = CommunityMaterial.Icon3.cmd_timetable icon = CommunityMaterial.Icon3.cmd_timetable
@ -83,7 +80,8 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
) { ) {
MessagesConfigDialog(activity, reloadOnDismiss = false).show() MessagesConfigDialog(activity, reloadOnDismiss = false).show()
}.takeIf { }.takeIf {
app.profile.hasUIFeature(FeatureType.MESSAGES_INBOX) || app.profile.hasUIFeature(FeatureType.MESSAGES_SENT) app.profile.hasUIFeature(FeatureType.MESSAGES_INBOX) || app.profile.hasUIFeature(
FeatureType.MESSAGES_SENT)
}, },
util.createActionItem( util.createActionItem(
@ -93,88 +91,90 @@ class SettingsRegisterCard(util: SettingsUtil) : SettingsCard(util) {
AttendanceConfigDialog(activity, reloadOnDismiss = false).show() AttendanceConfigDialog(activity, reloadOnDismiss = false).show()
}.takeIf { app.profile.hasUIFeature(FeatureType.ATTENDANCE) }, }.takeIf { app.profile.hasUIFeature(FeatureType.ATTENDANCE) },
if (app.profile.archived) util.createMoreItem(
null card = card,
else items = listOfNotNull(
util.createPropertyItem( util.createActionItem(
text = R.string.settings_register_allow_registration_text, text = R.string.settings_register_bell_sync_text,
subText = R.string.settings_register_allow_registration_subtext, icon = SzkolnyFont.Icon.szf_alarm_bell_outline,
icon = CommunityMaterial.Icon.cmd_account_circle_outline, onClick = {
value = app.profile.canShare, BellSyncConfigDialog(activity, onChangeListener = {
beforeChange = { item, value -> it.subText = getBellSync()
if (app.profile.canShare == value) util.refresh()
// allow the switch to change - needed for util.refresh() to change the visual state }).show()
return@createPropertyItem true }
val dialog = ).also {
RegistrationConfigDialog(activity, app.profile, onChangeListener = { enabled -> it.subText = getBellSync()
},
util.createPropertyItem(
text = R.string.settings_register_count_in_seconds_text,
subText = R.string.settings_register_count_in_seconds_subtext,
icon = CommunityMaterial.Icon3.cmd_timer_outline,
value = configGlobal.timetable.countInSeconds
) { _, it ->
configGlobal.timetable.countInSeconds = it
},
util.createPropertyItem(
text = R.string.settings_register_show_teacher_absences_text,
icon = CommunityMaterial.Icon.cmd_account_arrow_right_outline,
value = app.profile.getStudentData("showTeacherAbsences", true)
) { _, it ->
app.profile["showTeacherAbsences"] = it
app.profileSave()
}.takeIf { app.profile.loginStoreType == LoginType.LIBRUS },
util.createPropertyItem(
text = R.string.settings_register_hide_sticks_from_old,
icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline,
value = configProfile.grades.hideSticksFromOld
) { _, it ->
configProfile.grades.hideSticksFromOld = it
}.takeIf { App.devMode && app.profile.hasUIFeature(FeatureType.GRADES) },
),
),
*(getRegistrationItems().takeIf { !app.profile.archived } ?: arrayOf()),
)
private fun getRegistrationItems() = listOfNotNull(
util.createSectionItem(
text = R.string.settings_registration_section,
),
util.createPropertyItem(
text = R.string.settings_register_allow_registration_text,
subText = R.string.settings_register_allow_registration_subtext,
icon = CommunityMaterial.Icon.cmd_account_circle_outline,
value = app.profile.canShare,
beforeChange =
{ item, value ->
if (app.profile.canShare == value)
// allow the switch to change - needed for util.refresh() to change the visual state
return@createPropertyItem true
val dialog =
RegistrationConfigDialog(activity,
app.profile,
onChangeListener = { enabled ->
if (item.isChecked == enabled) if (item.isChecked == enabled)
return@RegistrationConfigDialog return@RegistrationConfigDialog
item.isChecked = enabled item.isChecked = enabled
if (value) { if (value) {
card.items.after(item, sharedEventsItem) card.items.after(item, sharedEventsDefaultItem)
} else { } else {
card.items.remove(sharedEventsItem) card.items.remove(sharedEventsDefaultItem)
} }
util.refresh() util.refresh()
}) })
if (value) if (value)
dialog.showEnableDialog() dialog.showEnableDialog()
else else
dialog.showDisableDialog() dialog.showDisableDialog()
false false
}
) { _, _ -> },
if (app.profile.canShare)
sharedEventsItem
else
null
)
override fun getItemsMore() = listOfNotNull(
util.createActionItem(
text = R.string.settings_register_bell_sync_text,
icon = SzkolnyFont.Icon.szf_alarm_bell_outline,
onClick = {
BellSyncConfigDialog(activity, onChangeListener = {
it.subText = getBellSync()
util.refresh()
}).show()
} }
).also { ) { _, _ -> },
it.subText = getBellSync()
},
util.createPropertyItem( sharedEventsDefaultItem.takeIf { app.profile.canShare },
text = R.string.settings_register_count_in_seconds_text, ).toTypedArray()
subText = R.string.settings_register_count_in_seconds_subtext,
icon = CommunityMaterial.Icon3.cmd_timer_outline,
value = configGlobal.timetable.countInSeconds
) { _, it ->
configGlobal.timetable.countInSeconds = it
},
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,
value = app.profile.getStudentData("showTeacherAbsences", true)
) { _, it ->
app.profile.putStudentData("showTeacherAbsences", it)
app.profileSave()
}
else
null,
if (App.devMode)
util.createPropertyItem(
text = R.string.settings_register_hide_sticks_from_old,
icon = CommunityMaterial.Icon3.cmd_numeric_1_box_outline,
value = configProfile.grades.hideSticksFromOld
) { _, it ->
configProfile.grades.hideSticksFromOld = it
}.takeIf { app.profile.hasUIFeature(FeatureType.GRADES) }
else
null
)
} }

View File

@ -10,6 +10,7 @@ import android.net.Uri
import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES import android.os.Build.VERSION_CODES
import android.provider.Settings import android.provider.Settings
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
@ -29,8 +30,8 @@ class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) {
override fun buildCard() = util.createCard( override fun buildCard() = util.createCard(
R.string.settings_card_sync_title, R.string.settings_card_sync_title,
items = getItems(), items = ::getItems,
itemsMore = getItemsMore() itemsMore = ::getItemsMore,
) )
private fun getQuietHours(): String { private fun getQuietHours(): String {
@ -63,7 +64,7 @@ class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) {
} }
} }
override fun getItems() = listOfNotNull( override fun getItems(card: MaterialAboutCard) = listOfNotNull(
util.createPropertyActionItem( util.createPropertyActionItem(
text = R.string.settings_sync_sync_interval_text, text = R.string.settings_sync_sync_interval_text,
subText = R.string.settings_sync_sync_interval_subtext_disabled, subText = R.string.settings_sync_sync_interval_subtext_disabled,
@ -156,7 +157,7 @@ class SettingsSyncCard(util: SettingsUtil) : SettingsCard(util) {
} }
) )
override fun getItemsMore() = listOfNotNull( override fun getItemsMore(card: MaterialAboutCard) = listOfNotNull(
util.createPropertyItem( util.createPropertyItem(
text = R.string.settings_sync_updates_text, text = R.string.settings_sync_updates_text,
icon = CommunityMaterial.Icon.cmd_cellphone_arrow_down, icon = CommunityMaterial.Icon.cmd_cellphone_arrow_down,

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.ui.settings.cards package pl.szczodrzynski.edziennik.ui.settings.cards
import com.danielstone.materialaboutlibrary.model.MaterialAboutCard
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
@ -20,11 +21,11 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
override fun buildCard() = util.createCard( override fun buildCard() = util.createCard(
R.string.settings_card_theme_title, R.string.settings_card_theme_title,
items = getItems(), items = ::getItems,
itemsMore = getItemsMore() itemsMore = ::getItemsMore,
) )
override fun getItems() = listOfNotNull( override fun getItems(card: MaterialAboutCard) = listOfNotNull(
if (Date.getToday().month % 11 == 1) // cool math games if (Date.getToday().month % 11 == 1) // cool math games
util.createPropertyItem( util.createPropertyItem(
text = R.string.settings_theme_snowfall_text, text = R.string.settings_theme_snowfall_text,
@ -76,7 +77,7 @@ class SettingsThemeCard(util: SettingsUtil) : SettingsCard(util) {
} }
) )
override fun getItemsMore() = listOf( override fun getItemsMore(card: MaterialAboutCard) = listOf(
util.createActionItem( util.createActionItem(
text = R.string.settings_theme_mini_drawer_buttons_text, text = R.string.settings_theme_mini_drawer_buttons_text,
icon = CommunityMaterial.Icon2.cmd_format_list_checks icon = CommunityMaterial.Icon2.cmd_format_list_checks

View File

@ -14,25 +14,48 @@ import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.asynclayoutinflater.view.AsyncLayoutInflater import androidx.asynclayoutinflater.view.AsyncLayoutInflater
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.view.* import androidx.core.view.isVisible
import androidx.core.view.marginTop
import androidx.core.view.setPadding
import androidx.core.view.updateLayoutParams
import androidx.core.view.updateMargins
import com.linkedin.android.tachyon.DayView import com.linkedin.android.tachyon.DayView
import com.linkedin.android.tachyon.DayViewConfig import com.linkedin.android.tachyon.DayViewConfig
import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.utils.colorInt import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.sizeDp import com.mikepenz.iconics.utils.sizeDp
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import pl.szczodrzynski.edziennik.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.db.entity.Lesson import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType 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.AttendanceFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.LessonFull import pl.szczodrzynski.edziennik.data.db.full.LessonFull
import pl.szczodrzynski.edziennik.databinding.TimetableDayFragmentBinding import pl.szczodrzynski.edziennik.databinding.TimetableDayFragmentBinding
import pl.szczodrzynski.edziennik.databinding.TimetableLessonBinding import pl.szczodrzynski.edziennik.databinding.TimetableLessonBinding
import pl.szczodrzynski.edziennik.databinding.TimetableNoTimetableBinding import pl.szczodrzynski.edziennik.databinding.TimetableNoTimetableBinding
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.Intent
import pl.szczodrzynski.edziennik.ext.JsonObject
import pl.szczodrzynski.edziennik.ext.asColoredSpannable
import pl.szczodrzynski.edziennik.ext.asStrikethroughSpannable
import pl.szczodrzynski.edziennik.ext.concat
import pl.szczodrzynski.edziennik.ext.dp
import pl.szczodrzynski.edziennik.ext.findParentById
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ext.listOfNotEmpty
import pl.szczodrzynski.edziennik.ext.onClick
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.resolveDrawable
import pl.szczodrzynski.edziennik.ext.setText
import pl.szczodrzynski.edziennik.ext.setTintColor
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment 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_END_HOUR
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_START_HOUR import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment.Companion.DEFAULT_START_HOUR
@ -76,7 +99,6 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
// find SwipeRefreshLayout in the hierarchy // find SwipeRefreshLayout in the hierarchy
private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) } private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) }
private val profileConfig by lazy { app.config.forProfile().ui }
private val dayViewDelegate = mutableLazy { private val dayViewDelegate = mutableLazy {
val dayView = DayView(activity, DayViewConfig( val dayView = DayView(activity, DayViewConfig(
@ -186,7 +208,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
val minStartHour = lessonsActual.minOf { it.displayStartTime?.hour ?: DEFAULT_END_HOUR } val minStartHour = lessonsActual.minOf { it.displayStartTime?.hour ?: DEFAULT_END_HOUR }
val maxEndHour = lessonsActual.maxOf { it.displayEndTime?.hour?.plus(1) ?: DEFAULT_START_HOUR } val maxEndHour = lessonsActual.maxOf { it.displayEndTime?.hour?.plus(1) ?: DEFAULT_START_HOUR }
if (profileConfig.timetableTrimHourRange) { if (app.profile.config.ui.timetableTrimHourRange) {
dayViewDelegate.deinitialize() dayViewDelegate.deinitialize()
// end/start defaults are swapped on purpose // end/start defaults are swapped on purpose
startHour = minStartHour startHour = minStartHour
@ -238,7 +260,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity) val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
for (lesson in lessons) { for (lesson in lessons) {
val attendance = if (profileConfig.timetableShowAttendance) val attendance = if (app.profile.config.ui.timetableShowAttendance)
attendanceList.find { it.startTime == lesson.startTime } attendanceList.find { it.startTime == lesson.startTime }
else else
null null
@ -272,7 +294,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
} }
val eventIcons = listOf(lb.event1, lb.event2, lb.event3) val eventIcons = listOf(lb.event1, lb.event2, lb.event3)
if (profileConfig.timetableShowEvents) { if (app.profile.config.ui.timetableShowEvents) {
val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3) val eventList = events.filter { it.time != null && it.time == lesson.displayStartTime }.take(3)
for ((i, eventIcon) in eventIcons.withIndex()) { for ((i, eventIcon) in eventIcons.withIndex()) {
eventList.getOrNull(i).let { eventList.getOrNull(i).let {
@ -323,7 +345,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
val lessonText = val lessonText =
lesson.getNoteSubstituteText(showNotes = true) ?: lesson.displaySubjectName lesson.getNoteSubstituteText(showNotes = true) ?: lesson.displaySubjectName
val (subjectTextPrimary, subjectTextSecondary) = if (profileConfig.timetableColorSubjectName) { val (subjectTextPrimary, subjectTextSecondary) = if (app.profile.config.ui.timetableColorSubjectName) {
val subjectColor = lesson.color ?: Colors.stringToMaterialColorCRC(lessonText?.toString() ?: "") val subjectColor = lesson.color ?: Colors.stringToMaterialColorCRC(lessonText?.toString() ?: "")
if (lb.annotationVisible) { if (lb.annotationVisible) {
lb.subjectContainer.background = ColorDrawable(subjectColor) lb.subjectContainer.background = ColorDrawable(subjectColor)

View File

@ -19,14 +19,18 @@ import androidx.viewpager.widget.ViewPager
import com.google.android.material.datepicker.MaterialDatePicker import com.google.android.material.datepicker.MaterialDatePicker
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import eu.szkolny.font.SzkolnyFont import eu.szkolny.font.SzkolnyFont
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R 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.data.db.enums.MetadataType
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding
import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains import pl.szczodrzynski.edziennik.ext.getSchoolYearConstrains
import pl.szczodrzynski.edziennik.ext.getStudentData
import pl.szczodrzynski.edziennik.ui.dialogs.settings.TimetableConfigDialog import pl.szczodrzynski.edziennik.ui.dialogs.settings.TimetableConfigDialog
import pl.szczodrzynski.edziennik.ui.event.EventManualDialog import pl.szczodrzynski.edziennik.ui.event.EventManualDialog
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
@ -54,7 +58,6 @@ class TimetableFragment : Fragment(), CoroutineScope {
private var fabShown = false private var fabShown = false
private val items = mutableListOf<Date>() private val items = mutableListOf<Date>()
private val profileConfig by lazy { app.config.forProfile().ui }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null activity = (getActivity() as MainActivity?) ?: return null

View File

@ -112,7 +112,7 @@ class DateDropdown : TextInputDropDown {
date.stepForward(0, 0, -weekDay + 7) date.stepForward(0, 0, -weekDay + 7)
weekDay = 0 weekDay = 0
// ALL SCHOOL DAYS OF THE NEXT WEEK // ALL SCHOOL DAYS OF THE NEXT WEEK
while (weekDay < 4) { while (weekDay < 5) {
dates += Item( dates += Item(
date.value.toLong(), date.value.toLong(),
context.getString(R.string.dialog_event_manual_date_next_week, Week.getFullDayName(weekDay), date.formattedString), context.getString(R.string.dialog_event_manual_date_next_week, Week.getFullDayName(weekDay), date.formattedString),

View File

@ -24,7 +24,7 @@ class AttendanceManager(val app: App) : CoroutineScope {
get() = job + Dispatchers.Default get() = job + Dispatchers.Default
val useSymbols val useSymbols
get() = app.config.forProfile().attendance.useSymbols get() = app.profile.config.attendance.useSymbols
fun getTypeShort(baseType: Int): String { fun getTypeShort(baseType: Int): String {
return when (baseType) { return when (baseType) {

View File

@ -55,7 +55,8 @@ class EventManager(val app: App) : CoroutineScope {
val hasReplacingNotes = event.hasReplacingNotes() val hasReplacingNotes = event.hasReplacingNotes()
title.text = listOfNotNull( title.text = listOfNotNull(
if (event.addedManually) "{cmd-clipboard-edit-outline} " else null, if (event.addedManually && !event.isSharedReceived) "{cmd-calendar-edit} " else null,
if (event.isSharedReceived) "{cmd-share-variant} " else null,
if (event.hasNotes() && hasReplacingNotes && showNotes) "{cmd-swap-horizontal} " else null, if (event.hasNotes() && hasReplacingNotes && showNotes) "{cmd-swap-horizontal} " else null,
if (event.hasNotes() && !hasReplacingNotes && showNotes) "{cmd-playlist-edit} " else null, if (event.hasNotes() && !hasReplacingNotes && showNotes) "{cmd-playlist-edit} " else null,
if (showType) "${event.typeName ?: "wydarzenie"} - " else null, if (showType) "${event.typeName ?: "wydarzenie"} - " else null,
@ -77,6 +78,8 @@ class EventManager(val app: App) : CoroutineScope {
fun setLegendText(legend: IconicsTextView, event: EventFull, showNotes: Boolean = true) { fun setLegendText(legend: IconicsTextView, event: EventFull, showNotes: Boolean = true) {
legend.text = listOfNotNull( legend.text = listOfNotNull(
if (event.addedManually) R.string.legend_event_added_manually else null, if (event.addedManually) R.string.legend_event_added_manually else null,
if (event.isSharedSent) R.string.legend_event_shared_sent else null,
if (event.isSharedReceived) R.string.legend_event_shared_received else null,
if (event.isDone) R.string.legend_event_is_done else null, if (event.isDone) R.string.legend_event_is_done else null,
if (showNotes) NoteManager.getLegendText(event) else null, if (showNotes) NoteManager.getLegendText(event) else null,
).map { legend.context.getString(it) }.join("\n") ).map { legend.context.getString(it) }.join("\n")

View File

@ -16,7 +16,13 @@ import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_AVG
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL
import pl.szczodrzynski.edziennik.data.db.full.GradeFull import pl.szczodrzynski.edziennik.data.db.full.GradeFull
import pl.szczodrzynski.edziennik.ext.* import pl.szczodrzynski.edziennik.ext.asColoredSpannable
import pl.szczodrzynski.edziennik.ext.get
import pl.szczodrzynski.edziennik.ext.ifNotNull
import pl.szczodrzynski.edziennik.ext.notEmptyOrNull
import pl.szczodrzynski.edziennik.ext.plural
import pl.szczodrzynski.edziennik.ext.resolveAttr
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
import pl.szczodrzynski.edziennik.ui.grades.models.GradesAverages import pl.szczodrzynski.edziennik.ui.grades.models.GradesAverages
import pl.szczodrzynski.edziennik.ui.grades.models.GradesSemester import pl.szczodrzynski.edziennik.ui.grades.models.GradesSemester
import java.text.DecimalFormat import java.text.DecimalFormat
@ -48,21 +54,21 @@ class GradesManager(val app: App) : CoroutineScope {
val orderBy val orderBy
get() = app.config.grades.orderBy get() = app.config.grades.orderBy
val yearAverageMode val yearAverageMode
get() = app.config.forProfile().grades.yearAverageMode get() = app.profile.config.grades.yearAverageMode
val colorMode val colorMode
get() = app.config.forProfile().grades.colorMode get() = app.profile.config.grades.colorMode
val plusValue val plusValue
get() = app.config.forProfile().grades.plusValue get() = app.profile.config.grades.plusValue
val minusValue val minusValue
get() = app.config.forProfile().grades.minusValue get() = app.profile.config.grades.minusValue
val dontCountEnabled val dontCountEnabled
get() = app.config.forProfile().grades.dontCountEnabled get() = app.profile.config.grades.dontCountEnabled
val dontCountGrades val dontCountGrades
get() = app.config.forProfile().grades.dontCountGrades get() = app.profile.config.grades.dontCountGrades
val hideImproved val hideImproved
get() = app.config.forProfile().grades.hideImproved get() = app.profile.config.grades.hideImproved
val averageWithoutWeight val averageWithoutWeight
get() = app.config.forProfile().grades.averageWithoutWeight get() = app.profile.config.grades.averageWithoutWeight
fun getOrderByString() = when (orderBy) { fun getOrderByString() = when (orderBy) {

View File

@ -80,7 +80,7 @@ class NoteManager(private val app: App) {
OwnerType.GRADE -> OwnerType.GRADE ->
app.db.gradeDao().getByIdNow(note.profileId, note.ownerId) app.db.gradeDao().getByIdNow(note.profileId, note.ownerId)
OwnerType.LESSON -> OwnerType.LESSON ->
app.db.timetableDao().getByIdNow(note.profileId, note.ownerId) app.db.timetableDao().getByOwnerIdNow(note.profileId, note.ownerId)
OwnerType.MESSAGE -> OwnerType.MESSAGE ->
app.db.messageDao().getByIdNow(note.profileId, note.ownerId) app.db.messageDao().getByIdNow(note.profileId, note.ownerId)
else -> null else -> null
@ -93,10 +93,15 @@ class NoteManager(private val app: App) {
return getOwner(note) != null 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 { val success = when {
!note.isShared && wasShared -> unshareNote(activity, note) !note.isShared && wasShared -> unshareNote(activity, note)
note.isShared -> shareNote(activity, note) note.isShared -> shareNote(activity, note, teamId)
else -> true else -> true
} }
@ -124,9 +129,9 @@ class NoteManager(private val app: App) {
return true 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) { return app.api.runCatching(activity) {
shareNote(note) shareNote(note, teamId)
} != null } != null
} }

View File

@ -92,6 +92,8 @@ class UpdateManager(val app: App) : CoroutineScope {
} }
fun notify(update: Update) { fun notify(update: Update) {
if (!app.config.sync.notifyAboutUpdates)
return
val bigText = listOf( val bigText = listOf(
app.getString(R.string.notification_updates_text, update.versionName), app.getString(R.string.notification_updates_text, update.versionName),
update.releaseNotes?.let { BetterHtml.fromHtml(context = null, it) }, update.releaseNotes?.let { BetterHtml.fromHtml(context = null, it) },

View File

@ -202,6 +202,7 @@ public class Date implements Comparable<Date>, Noteable {
return Week.getWeekDayFromDate(this); return Week.getWeekDayFromDate(this);
} }
@NonNull
public Date stepForward(int years, int months, int days) { public Date stepForward(int years, int months, int days) {
this.day += days; this.day += days;
if (day <= 0) { if (day <= 0) {
@ -425,4 +426,10 @@ public class Date implements Comparable<Date>, Noteable {
public boolean hasReplacingNotes() { public boolean hasReplacingNotes() {
return Noteable.DefaultImpls.hasReplacingNotes(this); return Noteable.DefaultImpls.hasReplacingNotes(this);
} }
@Nullable
@Override
public Long getNoteShareTeamId() {
return Noteable.DefaultImpls.getNoteShareTeamId(this);
}
} }

View File

@ -11,7 +11,7 @@
<variable <variable
name="config" name="config"
type="pl.szczodrzynski.edziennik.config.ProfileConfigUI" /> type="pl.szczodrzynski.edziennik.config.ProfileConfig" />
<variable <variable
name="isAgendaMode" name="isAgendaMode"
@ -38,7 +38,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:checked="@={config.agendaLessonChanges}" android:checked="@={config.ui.agendaLessonChanges}"
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_lesson_changes" /> android:text="@string/agenda_config_lesson_changes" />
@ -46,7 +46,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:checked="@={config.agendaTeacherAbsence}" android:checked="@={config.ui.agendaTeacherAbsence}"
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_teacher_absence" /> android:text="@string/agenda_config_teacher_absence" />
@ -54,7 +54,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:checked="@={config.agendaCompactMode}" android:checked="@={config.ui.agendaCompactMode}"
android:enabled="@{isAgendaMode}" android:enabled="@{isAgendaMode}"
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_compact_mode" android:text="@string/agenda_config_compact_mode"
@ -73,7 +73,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:checked="@={config.agendaGroupByType}" android:checked="@={config.ui.agendaGroupByType}"
android:enabled="@{isAgendaMode}" android:enabled="@{isAgendaMode}"
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_group_by_type" android:text="@string/agenda_config_group_by_type"
@ -101,6 +101,15 @@
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_event_sharing_enabled" /> android:text="@string/agenda_config_event_sharing_enabled" />
<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/shareByDefault"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:minHeight="32dp"
android:checked="@={config.shareByDefault}"
android:text="@string/settings_register_share_by_default_text" />
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -120,10 +129,9 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:checked="@={config.agendaElearningMark}" android:checked="@={config.ui.agendaElearningMark}"
android:enabled="false" android:enabled="false"
android:minHeight="32dp" android:minHeight="32dp"
android:onClick="@{() -> elearningType.setEnabled(elearningEnabled.isChecked())}"
android:text="@string/agenda_config_elearning_mark" /> android:text="@string/agenda_config_elearning_mark" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
@ -131,7 +139,7 @@
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:enabled="@{config.agendaElearningMark}" android:enabled="@{elearningEnabled.checked}"
android:hint="@string/agenda_config_elearning_type"> android:hint="@string/agenda_config_elearning_type">
<pl.szczodrzynski.edziennik.utils.TextInputDropDown <pl.szczodrzynski.edziennik.utils.TextInputDropDown
@ -147,7 +155,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:checked="@={config.agendaElearningGroup}" android:checked="@={config.ui.agendaElearningGroup}"
android:enabled="false" android:enabled="false"
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/agenda_config_elearning_group" /> android:text="@string/agenda_config_elearning_group" />

View File

@ -75,10 +75,17 @@
android:id="@+id/clearProfile" android:id="@+id/clearProfile"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="Clear all profile data" android:text="Clear all profile data"
android:textAllCaps="false" /> android:textAllCaps="false" />
<Button
android:id="@+id/clearEndpointTimers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:text="Clear endpoint timers (force full sync)"
android:textAllCaps="false" />
<Button <Button
android:id="@+id/rodo" android:id="@+id/rodo"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -18,6 +18,10 @@
<variable <variable
name="editingNote" name="editingNote"
type="Note" /> type="Note" />
<variable
name="shareByDefault"
type="boolean" />
</data> </data>
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
@ -89,7 +93,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:checked="@{editingNote.sharedBy != null}" android:checked="@{editingNote.sharedBy != null || editingNote == null &amp;&amp; shareByDefault}"
android:isVisible="@{ownerType.shareable}" android:isVisible="@{ownerType.shareable}"
android:minHeight="32dp" android:minHeight="32dp"
android:text="@string/dialog_event_manual_share_enabled" /> android:text="@string/dialog_event_manual_share_enabled" />

View File

@ -1,5 +1,6 @@
{ {
"base": { "base": {
"configOverrides": {},
"messagesConfig": { "messagesConfig": {
"subjectLength": null, "subjectLength": null,
"bodyLength": null, "bodyLength": null,
@ -82,8 +83,9 @@
}, },
"university": { "university": {
"configOverrides": { "configOverrides": {
"timetableTrimHourRange": true, "shareByDefault": true,
"timetableColorSubjectName": true "timetableColorSubjectName": true,
"timetableTrimHourRange": true
}, },
"uiConfig": { "uiConfig": {
"lessonHeight": 45 "lessonHeight": 45

View File

@ -847,7 +847,7 @@
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string> <string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string> <string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
<string name="settings_card_register_title">E-Klassenbuch</string> <string name="settings_card_register_title">E-Klassenbuch</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - 2022</string> <string name="settings_about_title_subtext">© Kuba Szczodrzyński, September 2018 - 2022</string>
<string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string> <string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string>
<string name="settings_about_update_text">Aktualisierung</string> <string name="settings_about_update_text">Aktualisierung</string>
<string name="settings_about_version_text">Version</string> <string name="settings_about_version_text">Version</string>
@ -898,10 +898,6 @@
<string name="settings_register_count_in_seconds_text">Zählen Sie die Zeit in Sekunden herunter</string> <string name="settings_register_count_in_seconds_text">Zählen Sie die Zeit in Sekunden herunter</string>
<string name="settings_register_dont_count_zero_text">Zählen Sie die Note 0 nicht zum Durchschnitt</string> <string name="settings_register_dont_count_zero_text">Zählen Sie die Note 0 nicht zum Durchschnitt</string>
<string name="settings_register_login_not_implemented_text">Dieses E-Register ist noch nicht implementiert</string> <string name="settings_register_login_not_implemented_text">Dieses E-Register ist noch nicht implementiert</string>
<string name="settings_register_shared_events_dialog_disabled_text">Sie erhalten keine geteilten Ereignisse mehr und können sie nicht mehr teilen.</string>
<string name="settings_register_shared_events_dialog_enabled_text">Sie erhalten geteilte Ereignisse von anderen Personen in Ihrer Klasse</string>
<string name="settings_register_shared_events_subtext">Teile Tests in deiner Klasse</string>
<string name="settings_register_shared_events_text">Aktivieren Sie die Ereignisfreigabe</string>
<string name="settings_register_show_teacher_absences_text">Zeigen Sie die Abwesenheiten von Lehrern im Zeitplan an</string> <string name="settings_register_show_teacher_absences_text">Zeigen Sie die Abwesenheiten von Lehrern im Zeitplan an</string>
<string name="settings_sync_customize_endpoint_announcements">Schwarzes Brett</string> <string name="settings_sync_customize_endpoint_announcements">Schwarzes Brett</string>
<string name="settings_sync_customize_endpoint_attendance">Anwesenheiten</string> <string name="settings_sync_customize_endpoint_attendance">Anwesenheiten</string>

View File

@ -849,7 +849,7 @@
<string name="settings_about_licenses_text">Open-source licenses</string> <string name="settings_about_licenses_text">Open-source licenses</string>
<string name="settings_about_privacy_policy_text">Privacy policy</string> <string name="settings_about_privacy_policy_text">Privacy policy</string>
<string name="settings_card_register_title">E-register</string> <string name="settings_card_register_title">E-register</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 2022</string> <string name="settings_about_title_subtext">© Kuba Szczodrzyński, September 2018 2022</string>
<string name="settings_about_update_subtext">Click to check for updates</string> <string name="settings_about_update_subtext">Click to check for updates</string>
<string name="settings_about_update_text">Update</string> <string name="settings_about_update_text">Update</string>
<string name="settings_about_version_text">Version</string> <string name="settings_about_version_text">Version</string>
@ -900,10 +900,6 @@
<string name="settings_register_count_in_seconds_text">Count time in seconds</string> <string name="settings_register_count_in_seconds_text">Count time in seconds</string>
<string name="settings_register_dont_count_zero_text">Don\'t count 0 grade to average</string> <string name="settings_register_dont_count_zero_text">Don\'t count 0 grade to average</string>
<string name="settings_register_login_not_implemented_text">This e-register isn\'t implemented yet.</string> <string name="settings_register_login_not_implemented_text">This e-register isn\'t implemented yet.</string>
<string name="settings_register_shared_events_dialog_disabled_text">You won\'t receive shared events anymore and you won\'t be able to share them.</string>
<string name="settings_register_shared_events_dialog_enabled_text">You will receive shared events from other people in your class.</string>
<string name="settings_register_shared_events_subtext">Share exams in your class</string>
<string name="settings_register_shared_events_text">Enable Event sharing</string>
<string name="settings_register_show_teacher_absences_text">Show teacher absences in Agenda</string> <string name="settings_register_show_teacher_absences_text">Show teacher absences in Agenda</string>
<string name="settings_sync_customize_endpoint_announcements">Notice board</string> <string name="settings_sync_customize_endpoint_announcements">Notice board</string>
<string name="settings_sync_customize_endpoint_attendance">Attendances</string> <string name="settings_sync_customize_endpoint_attendance">Attendances</string>

View File

@ -916,7 +916,7 @@
<string name="settings_about_licenses_text">Licencje open-source</string> <string name="settings_about_licenses_text">Licencje open-source</string>
<string name="settings_about_privacy_policy_text">Polityka prywatności</string> <string name="settings_about_privacy_policy_text">Polityka prywatności</string>
<string name="settings_card_register_title">E-dziennik</string> <string name="settings_card_register_title">E-dziennik</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nwrzesień 2018 - 2022</string> <string name="settings_about_title_subtext">© Kuba Szczodrzyński, wrzesień 2018 - 2022</string>
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string> <string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
<string name="settings_about_update_text">Aktualizacja</string> <string name="settings_about_update_text">Aktualizacja</string>
<string name="settings_about_version_text">Wersja</string> <string name="settings_about_version_text">Wersja</string>
@ -969,10 +969,6 @@
<string name="settings_register_count_in_seconds_text">Odliczaj czas w sekundach</string> <string name="settings_register_count_in_seconds_text">Odliczaj czas w sekundach</string>
<string name="settings_register_dont_count_zero_text">Nie wliczaj oceny 0 do średniej</string> <string name="settings_register_dont_count_zero_text">Nie wliczaj oceny 0 do średniej</string>
<string name="settings_register_login_not_implemented_text">Ten e-dziennik nie został jeszcze zaimplementowany w aplikacji.</string> <string name="settings_register_login_not_implemented_text">Ten e-dziennik nie został jeszcze zaimplementowany w aplikacji.</string>
<string name="settings_register_shared_events_dialog_disabled_text">Nie będziesz już otrzymywać udostępnionych sprawdzianów i nie będziesz mógł ich też udostępnić.</string>
<string name="settings_register_shared_events_dialog_enabled_text">Będziesz otrzymywać udostępnione sprawdziany od innych osób z twojej klasy.</string>
<string name="settings_register_shared_events_subtext">Udostępniaj sprawdziany w swojej klasie</string>
<string name="settings_register_shared_events_text">Włącz Udostępnianie wydarzeń</string>
<string name="settings_register_show_teacher_absences_text">Pokazuj nieobecności nauczycieli w Terminarzu</string> <string name="settings_register_show_teacher_absences_text">Pokazuj nieobecności nauczycieli w Terminarzu</string>
<string name="settings_sync_customize_endpoint_announcements">Tablica ogłoszeń</string> <string name="settings_sync_customize_endpoint_announcements">Tablica ogłoszeń</string>
<string name="settings_sync_customize_endpoint_attendance">Obecności/nieobecności</string> <string name="settings_sync_customize_endpoint_attendance">Obecności/nieobecności</string>
@ -1437,7 +1433,7 @@
<string name="agenda_config_elearning_mark">Ustaw wydarzenia jako lekcje on-line</string> <string name="agenda_config_elearning_mark">Ustaw wydarzenia jako lekcje on-line</string>
<string name="agenda_config_elearning_type">Wybierz rodzaj wydarzeń</string> <string name="agenda_config_elearning_type">Wybierz rodzaj wydarzeń</string>
<string name="agenda_config_elearning_group">Grupuj lekcje on-line na liście</string> <string name="agenda_config_elearning_group">Grupuj lekcje on-line na liście</string>
<string name="legend_event_added_manually">{cmd-clipboard-edit-outline} wydarzenie dodane ręcznie</string> <string name="legend_event_added_manually">{cmd-calendar-edit} wydarzenie dodane ręcznie</string>
<string name="legend_event_is_done">{cmd-check} oznaczono jako wykonane</string> <string name="legend_event_is_done">{cmd-check} oznaczono jako wykonane</string>
<string name="agenda_config_not_available_yet">Funkcja jeszcze nie jest dostępna.</string> <string name="agenda_config_not_available_yet">Funkcja jeszcze nie jest dostępna.</string>
<string name="messages_config_compose">Tworzenie wiadomości</string> <string name="messages_config_compose">Tworzenie wiadomości</string>
@ -1549,4 +1545,10 @@
<string name="notification_user_action_required_oauth_usos">USOS - wymagane logowanie z użyciem przeglądarki</string> <string name="notification_user_action_required_oauth_usos">USOS - wymagane logowanie z użyciem przeglądarki</string>
<string name="oauth_dialog_title">Zaloguj się</string> <string name="oauth_dialog_title">Zaloguj się</string>
<string name="app_cannot_load_data">Nie można załadować danych aplikacji</string> <string name="app_cannot_load_data">Nie można załadować danych aplikacji</string>
<string name="legend_event_shared_received">{cmd-share-variant} udostępnione w klasie</string>
<string name="legend_event_shared_sent">{cmd-share-variant} udostępnione przez Ciebie</string>
<string name="settings_register_share_by_default_text">Domyślnie udostępniaj wydarzenia</string>
<string name="settings_register_share_by_default_subtext">Ustaw tworzone wydarzenia domyślnie jako udostępnione</string>
<string name="settings_registration_section">Rejestracja</string>
<string name="home_timetable_all_lessons">Wszystkie lekcje:</string>
</resources> </resources>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.6.10' kotlin_version = '1.6.10'
release = [ release = [
versionName: "4.13-rc.2", versionName: "4.13",
versionCode: 4130020 versionCode: 4130099
] ]
setup = [ setup = [