mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2024-11-24 10:54:36 -06:00
[App] Move per-register settings to JSON resource. Rewrite Config to use delegates. (#150)
* [App] Add base for AppData loading. * [UI] Fix timetable widget date navigation. * [UI] Migrate register-specific behavior to use AppData. * [App] Implement new delegate-based config base. * [Config] Migrate config and profile config. * [Config] Remove defaults from migrations. * [App] Apply event types and config overrides from AppData. * [Events] Change default event types for university type school.
This commit is contained in:
parent
6c93cd4217
commit
63c5720f63
@ -4,6 +4,13 @@
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="4" />
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
<option name="SMART_TABS" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||
<indentOptions>
|
||||
|
@ -5,6 +5,7 @@
|
||||
<w>ciasteczko</w>
|
||||
<w>csrf</w>
|
||||
<w>edziennik</w>
|
||||
<w>eggfall</w>
|
||||
<w>elearning</w>
|
||||
<w>gson</w>
|
||||
<w>hebe</w>
|
||||
|
@ -12,6 +12,7 @@ import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import androidx.work.Configuration
|
||||
@ -31,6 +32,7 @@ import kotlinx.coroutines.*
|
||||
import me.leolin.shortcutbadger.ShortcutBadger
|
||||
import okhttp3.OkHttpClient
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.config.AppData
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ProfileListEmptyEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||
@ -48,18 +50,27 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||
import pl.szczodrzynski.edziennik.ui.base.CrashActivity
|
||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||
import pl.szczodrzynski.edziennik.utils.*
|
||||
import pl.szczodrzynski.edziennik.utils.DebugLogFormat
|
||||
import pl.szczodrzynski.edziennik.utils.PermissionChecker
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.managers.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
companion object {
|
||||
@Volatile
|
||||
lateinit var db: AppDb
|
||||
private set
|
||||
lateinit var config: Config
|
||||
// private set // for LabFragment
|
||||
lateinit var profile: Profile
|
||||
private set
|
||||
lateinit var data: AppData
|
||||
private set
|
||||
val profileId
|
||||
get() = profile.id
|
||||
|
||||
@ -90,6 +101,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
get() = App.profile
|
||||
val profileId
|
||||
get() = App.profileId
|
||||
val data
|
||||
get() = App.data
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
@ -124,9 +137,6 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
SSLProviderInstaller.enableSupportedTls(builder, enableCleartext = true)
|
||||
|
||||
if (devMode) {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
if (enableChucker) {
|
||||
val chuckerCollector = ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR)
|
||||
val chuckerInterceptor = ChuckerInterceptor(this, chuckerCollector)
|
||||
@ -180,16 +190,24 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
Iconics.init(applicationContext)
|
||||
Iconics.respectFontBoundsDefault = true
|
||||
|
||||
if (devMode) {
|
||||
HyperLog.initialize(this)
|
||||
HyperLog.setLogLevel(Log.VERBOSE)
|
||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||
}
|
||||
|
||||
// initialize companion object values
|
||||
AppData.read(this)
|
||||
App.db = AppDb(this)
|
||||
App.config = Config(App.db)
|
||||
App.profile = Profile(0, 0, LoginType.TEMPLATE, "")
|
||||
debugMode = BuildConfig.DEBUG
|
||||
devMode = config.devMode ?: debugMode
|
||||
enableChucker = config.enableChucker ?: devMode
|
||||
|
||||
if (!profileLoadById(config.lastProfileId)) {
|
||||
db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
val success = db.profileDao().firstId?.let { profileLoadById(it) }
|
||||
if (success != true)
|
||||
profileLoad(Profile(0, 0, LoginType.TEMPLATE, ""))
|
||||
}
|
||||
|
||||
buildHttp()
|
||||
@ -381,10 +399,22 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
fun profileLoad(profile: Profile) {
|
||||
App.profile = profile
|
||||
App.config.lastProfileId = profile.id
|
||||
try {
|
||||
App.data = AppData.get(profile.loginStoreType)
|
||||
d("App", "Loaded AppData: ${App.data}")
|
||||
} catch (e: Exception) {
|
||||
Log.e("App", "Cannot load AppData", e)
|
||||
Toast.makeText(this, R.string.app_cannot_load_data, Toast.LENGTH_LONG).show()
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun profileLoadById(profileId: Int): Boolean {
|
||||
db.profileDao().getByIdNow(profileId)?.also {
|
||||
App.profile = it
|
||||
App.config.lastProfileId = it.id
|
||||
profileLoad(it)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -42,7 +42,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
@ -427,7 +426,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
launch {
|
||||
withContext(Dispatchers.Default) {
|
||||
app.db.profileDao().allNow.forEach { profile ->
|
||||
if (profile.loginStoreType != LoginType.LIBRUS)
|
||||
if (!profile.getAppData().uiConfig.enableMarkAsReadAnnouncements)
|
||||
app.db.metadataDao()
|
||||
.setAllSeenExceptMessagesAndAnnouncements(profile.id, true)
|
||||
else
|
||||
@ -695,7 +694,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
d(TAG, "}")
|
||||
|
||||
val intentProfileId = extras.getIntOrNull("profileId")
|
||||
val intentProfileId = extras.getIntOrNull("profileId").takePositive()
|
||||
var intentNavTarget = extras.getIntOrNull("fragmentId").asNavTargetOrNull()
|
||||
|
||||
if (extras?.containsKey("action") == true) {
|
||||
@ -743,8 +742,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
|
||||
if (extras?.containsKey("reloadProfileId") == true) {
|
||||
val reloadProfileId = extras.getIntOrNull("reloadProfileId")
|
||||
if (reloadProfileId == -1 || app.profile.id == reloadProfileId) {
|
||||
val reloadProfileId = extras.getIntOrNull("reloadProfileId").takePositive()
|
||||
if (reloadProfileId == null || app.profile.id == reloadProfileId) {
|
||||
reloadTarget()
|
||||
return
|
||||
}
|
||||
@ -767,7 +766,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
navTarget = intentNavTarget,
|
||||
args = extras,
|
||||
)
|
||||
intentProfileId != -1 -> navigate(
|
||||
intentProfileId != null -> navigate(
|
||||
profileId = intentProfileId,
|
||||
navTarget = intentNavTarget,
|
||||
args = extras,
|
||||
@ -776,6 +775,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
navTarget = intentNavTarget,
|
||||
args = extras,
|
||||
)
|
||||
navLoading -> navigate()
|
||||
else -> drawer.currentProfile = app.profile.id
|
||||
}
|
||||
navLoading = false
|
||||
@ -923,7 +923,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
||||
}
|
||||
|
||||
if (profileChanged) {
|
||||
App.profile = profile
|
||||
if (App.profileId != profile.id)
|
||||
app.profileLoad(profile)
|
||||
MessagesFragment.pageSelection = -1
|
||||
// set new drawer items for this profile
|
||||
setDrawerItems()
|
||||
|
@ -1,9 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
interface AbstractConfig {
|
||||
fun set(key: String, value: String?)
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2022-10-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.google.gson.stream.JsonReader
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.ext.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.ext.mergeWith
|
||||
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode
|
||||
|
||||
data class AppData(
|
||||
val configOverrides: Map<String, String>,
|
||||
val messagesConfig: MessagesConfig,
|
||||
val uiConfig: UIConfig,
|
||||
val eventTypes: List<EventType>,
|
||||
) {
|
||||
companion object {
|
||||
private var data: JsonObject? = null
|
||||
private val appData = mutableMapOf<LoginType, AppData>()
|
||||
|
||||
fun read(app: App) {
|
||||
val res = app.resources.openRawResource(R.raw.app_data)
|
||||
data = JsonParser.parseReader(JsonReader(res.reader())).asJsonObject
|
||||
}
|
||||
|
||||
fun get(loginType: LoginType): AppData {
|
||||
if (loginType in appData)
|
||||
return appData.getValue(loginType)
|
||||
val json = data?.getJsonObject("base")?.deepCopy()
|
||||
?: throw NoSuchElementException("Base data not found")
|
||||
val overrides = setOf(loginType, loginType.schoolType)
|
||||
for (overrideType in overrides) {
|
||||
val override = data?.getJsonObject(overrideType.name.lowercase()) ?: continue
|
||||
json.mergeWith(override)
|
||||
}
|
||||
val value = Gson().fromJson(json, AppData::class.java)
|
||||
appData[loginType] = value
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
data class MessagesConfig(
|
||||
val subjectLength: Int?,
|
||||
val bodyLength: Int?,
|
||||
val textStyling: Boolean,
|
||||
val syncRecipientList: Boolean,
|
||||
val htmlMode: HtmlMode,
|
||||
val needsReadStatus: Boolean,
|
||||
)
|
||||
|
||||
data class UIConfig(
|
||||
val lessonHeight: Int,
|
||||
val enableMarkAsReadAnnouncements: Boolean,
|
||||
val enableNoticePoints: Boolean,
|
||||
)
|
||||
|
||||
data class EventType(
|
||||
val id: Int,
|
||||
val color: String,
|
||||
val name: String,
|
||||
)
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import pl.szczodrzynski.edziennik.ext.takePositive
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
abstract class BaseConfig(
|
||||
val db: AppDb,
|
||||
val profileId: Int? = null,
|
||||
protected var entries: List<ConfigEntry>? = null,
|
||||
) : CoroutineScope {
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values = hashMapOf<String, String?>()
|
||||
|
||||
init {
|
||||
if (entries == null)
|
||||
entries = db.configDao().getAllNow()
|
||||
values.clear()
|
||||
for ((profileId, key, value) in entries!!) {
|
||||
if (profileId.takePositive() != this.profileId)
|
||||
continue
|
||||
values[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
fun set(key: String, value: String?) {
|
||||
values[key] = value
|
||||
launch(Dispatchers.IO) {
|
||||
db.configDao().add(ConfigEntry(profileId ?: -1, key, value))
|
||||
}
|
||||
}
|
||||
}
|
@ -5,151 +5,59 @@
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.config.utils.*
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class Config(db: AppDb) : BaseConfig(db) {
|
||||
companion object {
|
||||
const val DATA_VERSION = 12
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
|
||||
val ui by lazy { ConfigUI(this) }
|
||||
val sync by lazy { ConfigSync(this) }
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
val grades by lazy { ConfigGrades(this) }
|
||||
|
||||
private var mDataVersion: Int? = null
|
||||
var dataVersion: Int
|
||||
get() { mDataVersion = mDataVersion ?: values.get("dataVersion", 0); return mDataVersion ?: 0 }
|
||||
set(value) { set("dataVersion", value); mDataVersion = value }
|
||||
var dataVersion by config<Int>(0)
|
||||
var hash by config<String>("")
|
||||
|
||||
private var mHash: String? = null
|
||||
var hash: String
|
||||
get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
|
||||
set(value) { set("hash", value); mHash = value }
|
||||
var lastProfileId by config<Int>(0)
|
||||
var loginFinished by config<Boolean>(false)
|
||||
var privacyPolicyAccepted by config<Boolean>(false)
|
||||
var update by config<Update?>(null)
|
||||
var updatesChannel by config<String>("release")
|
||||
|
||||
private var mLastProfileId: Int? = null
|
||||
var lastProfileId: Int
|
||||
get() { mLastProfileId = mLastProfileId ?: values.get("lastProfileId", 0); return mLastProfileId ?: 0 }
|
||||
set(value) { set("lastProfileId", value); mLastProfileId = value }
|
||||
var devMode by config<Boolean?>(null)
|
||||
var devModePassword by config<String?>(null)
|
||||
var enableChucker by config<Boolean?>(null)
|
||||
|
||||
private var mUpdatesChannel: String? = null
|
||||
var updatesChannel: String
|
||||
get() { mUpdatesChannel = mUpdatesChannel ?: values.get("updatesChannel", "release"); return mUpdatesChannel ?: "release" }
|
||||
set(value) { set("updatesChannel", value); mUpdatesChannel = value }
|
||||
private var mUpdate: Update? = null
|
||||
var update: Update?
|
||||
get() { mUpdate = mUpdate ?: values.get("update", null as Update?); return mUpdate ?: null as Update? }
|
||||
set(value) { set("update", value); mUpdate = value }
|
||||
var apiAvailabilityCheck by config<Boolean>(true)
|
||||
var apiInvalidCert by config<String?>(null)
|
||||
var appInstalledTime by config<Long>(0L)
|
||||
var appRateSnackbarTime by config<Long>(0L)
|
||||
var appVersion by config<Int>(BuildConfig.VERSION_CODE)
|
||||
var validation by config<String?>(null, "buildValidation")
|
||||
|
||||
private var mAppVersion: Int? = null
|
||||
var appVersion: Int
|
||||
get() { mAppVersion = mAppVersion ?: values.get("appVersion", BuildConfig.VERSION_CODE); return mAppVersion ?: BuildConfig.VERSION_CODE }
|
||||
set(value) { set("appVersion", value); mAppVersion = value }
|
||||
var archiverEnabled by config<Boolean>(true)
|
||||
var runSync by config<Boolean>(false)
|
||||
var widgetConfigs by config<JsonObject> { JsonObject() }
|
||||
|
||||
private var mLoginFinished: Boolean? = null
|
||||
var loginFinished: Boolean
|
||||
get() { mLoginFinished = mLoginFinished ?: values.get("loginFinished", false); return mLoginFinished ?: false }
|
||||
set(value) { set("loginFinished", value); mLoginFinished = value }
|
||||
|
||||
private var mPrivacyPolicyAccepted: Boolean? = null
|
||||
var privacyPolicyAccepted: Boolean
|
||||
get() { mPrivacyPolicyAccepted = mPrivacyPolicyAccepted ?: values.get("privacyPolicyAccepted", false); return mPrivacyPolicyAccepted ?: false }
|
||||
set(value) { set("privacyPolicyAccepted", value); mPrivacyPolicyAccepted = value }
|
||||
|
||||
private var mDevMode: Boolean? = null
|
||||
var devMode: Boolean?
|
||||
get() { mDevMode = mDevMode ?: values.getBooleanOrNull("debugMode"); return mDevMode }
|
||||
set(value) { set("debugMode", value?.toString()); mDevMode = value }
|
||||
|
||||
private var mEnableChucker: Boolean? = null
|
||||
var enableChucker: Boolean?
|
||||
get() { mEnableChucker = mEnableChucker ?: values.getBooleanOrNull("enableChucker"); return mEnableChucker }
|
||||
set(value) { set("enableChucker", value?.toString()); mEnableChucker = value }
|
||||
|
||||
private var mDevModePassword: String? = null
|
||||
var devModePassword: String?
|
||||
get() { mDevModePassword = mDevModePassword ?: values.get("devModePassword", null as String?); return mDevModePassword }
|
||||
set(value) { set("devModePassword", value); mDevModePassword = value }
|
||||
|
||||
private var mAppInstalledTime: Long? = null
|
||||
var appInstalledTime: Long
|
||||
get() { mAppInstalledTime = mAppInstalledTime ?: values.get("appInstalledTime", 0L); return mAppInstalledTime ?: 0L }
|
||||
set(value) { set("appInstalledTime", value); mAppInstalledTime = value }
|
||||
|
||||
private var mAppRateSnackbarTime: Long? = null
|
||||
var appRateSnackbarTime: Long
|
||||
get() { mAppRateSnackbarTime = mAppRateSnackbarTime ?: values.get("appRateSnackbarTime", 0L); return mAppRateSnackbarTime ?: 0L }
|
||||
set(value) { set("appRateSnackbarTime", value); mAppRateSnackbarTime = value }
|
||||
|
||||
private var mRunSync: Boolean? = null
|
||||
var runSync: Boolean
|
||||
get() { mRunSync = mRunSync ?: values.get("runSync", false); return mRunSync ?: false }
|
||||
set(value) { set("runSync", value); mRunSync = value }
|
||||
|
||||
private var mWidgetConfigs: JsonObject? = null
|
||||
var widgetConfigs: JsonObject
|
||||
get() { mWidgetConfigs = mWidgetConfigs ?: values.get("widgetConfigs", JsonObject()); return mWidgetConfigs ?: JsonObject() }
|
||||
set(value) { set("widgetConfigs", value); mWidgetConfigs = value }
|
||||
|
||||
private var mArchiverEnabled: Boolean? = null
|
||||
var archiverEnabled: Boolean
|
||||
get() { mArchiverEnabled = mArchiverEnabled ?: values.get("archiverEnabled", true); return mArchiverEnabled ?: true }
|
||||
set(value) { set("archiverEnabled", value); mArchiverEnabled = value }
|
||||
|
||||
private var mValidation: String? = null
|
||||
var validation: String?
|
||||
get() { mValidation = mValidation ?: values["buildValidation"]; return mValidation }
|
||||
set(value) { set("buildValidation", value); mValidation = value }
|
||||
|
||||
private var mApiInvalidCert: String? = null
|
||||
var apiInvalidCert: String?
|
||||
get() { mApiInvalidCert = mApiInvalidCert ?: values["apiInvalidCert"]; return mApiInvalidCert }
|
||||
set(value) { set("apiInvalidCert", value); mApiInvalidCert = value }
|
||||
|
||||
private var mApiAvailabilityCheck: Boolean? = null
|
||||
var apiAvailabilityCheck: Boolean
|
||||
get() { mApiAvailabilityCheck = mApiAvailabilityCheck ?: values.get("apiAvailabilityCheck", true); return mApiAvailabilityCheck ?: true }
|
||||
set(value) { set("apiAvailabilityCheck", value); mApiAvailabilityCheck = value }
|
||||
|
||||
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
init {
|
||||
rawEntries.toHashMap(-1, values)
|
||||
}
|
||||
fun migrate(app: App) {
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ConfigMigration(app, this)
|
||||
}
|
||||
|
||||
fun getFor(profileId: Int): ProfileConfig {
|
||||
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, db.configDao().getAllNow(profileId)).also {
|
||||
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, entries).also {
|
||||
profileConfigs[profileId] = it
|
||||
}
|
||||
}
|
||||
|
||||
fun forProfile() = getFor(App.profileId)
|
||||
|
||||
fun setProfile(profileId: Int) {
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
values[key] = value
|
||||
launch {
|
||||
db.configDao().add(ConfigEntry(-1, key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,10 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC
|
||||
|
||||
class ConfigGrades(private val config: Config) {
|
||||
private var mOrderBy: Int? = null
|
||||
var orderBy: Int
|
||||
get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: GradesManager.ORDER_BY_DATE_DESC }
|
||||
set(value) { config.set("gradesOrderBy", value); mOrderBy = value }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigGrades(base: Config) {
|
||||
|
||||
var orderBy by base.config<Int>("gradesOrderBy", ORDER_BY_DATE_DESC)
|
||||
}
|
||||
|
@ -4,139 +4,53 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.config.utils.setMap
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
||||
import pl.szczodrzynski.edziennik.ext.HOUR
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigSync(private val config: Config) {
|
||||
private val gson = Gson()
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigSync(base: Config) {
|
||||
|
||||
private var mDontShowAppManagerDialog: Boolean? = null
|
||||
var dontShowAppManagerDialog: Boolean
|
||||
get() { mDontShowAppManagerDialog = mDontShowAppManagerDialog ?: config.values.get("dontShowAppManagerDialog", false); return mDontShowAppManagerDialog ?: false }
|
||||
set(value) { config.set("dontShowAppManagerDialog", value); mDontShowAppManagerDialog = value }
|
||||
var enabled by base.config<Boolean>("syncEnabled", true)
|
||||
var interval by base.config<Int>("syncInterval", 1 * HOUR.toInt())
|
||||
var onlyWifi by base.config<Boolean>("syncOnlyWifi", false)
|
||||
|
||||
private var mSyncEnabled: Boolean? = null
|
||||
var enabled: Boolean
|
||||
get() { mSyncEnabled = mSyncEnabled ?: config.values.get("syncEnabled", true); return mSyncEnabled ?: true }
|
||||
set(value) { config.set("syncEnabled", value); mSyncEnabled = value }
|
||||
var dontShowAppManagerDialog by base.config<Boolean>(false)
|
||||
var lastAppSync by base.config<Long>(0L)
|
||||
var notifyAboutUpdates by base.config<Boolean>(true)
|
||||
var webPushEnabled by base.config<Boolean>(true)
|
||||
|
||||
private var mWebPushEnabled: Boolean? = null
|
||||
var webPushEnabled: Boolean
|
||||
get() { mWebPushEnabled = mWebPushEnabled ?: config.values.get("webPushEnabled", true); return mWebPushEnabled ?: true }
|
||||
set(value) { config.set("webPushEnabled", value); mWebPushEnabled = value }
|
||||
// Quiet Hours
|
||||
var quietHoursEnabled by base.config<Boolean>(false)
|
||||
var quietHoursStart by base.config<Time?>(null)
|
||||
var quietHoursEnd by base.config<Time?>(null)
|
||||
var quietDuringLessons by base.config<Boolean>(false)
|
||||
|
||||
private var mSyncOnlyWifi: Boolean? = null
|
||||
var onlyWifi: Boolean
|
||||
get() { mSyncOnlyWifi = mSyncOnlyWifi ?: config.values.get("syncOnlyWifi", false); return mSyncOnlyWifi ?: notifyAboutUpdates }
|
||||
set(value) { config.set("syncOnlyWifi", value); mSyncOnlyWifi = value }
|
||||
// FCM Tokens
|
||||
var tokenApp by base.config<String?>(null)
|
||||
var tokenMobidziennik by base.config<String?>(null)
|
||||
var tokenLibrus by base.config<String?>(null)
|
||||
var tokenVulcan by base.config<String?>(null)
|
||||
var tokenVulcanHebe by base.config<String?>(null)
|
||||
|
||||
private var mSyncInterval: Int? = null
|
||||
var interval: Int
|
||||
get() { mSyncInterval = mSyncInterval ?: config.values.get("syncInterval", 60*60); return mSyncInterval ?: 60*60 }
|
||||
set(value) { config.set("syncInterval", value); mSyncInterval = value }
|
||||
var tokenMobidziennikList by base.config<List<Int>> { listOf() }
|
||||
var tokenLibrusList by base.config<List<Int>> { listOf() }
|
||||
var tokenVulcanList by base.config<List<Int>> { listOf() }
|
||||
var tokenVulcanHebeList by base.config<List<Int>> { listOf() }
|
||||
|
||||
private var mNotifyAboutUpdates: Boolean? = null
|
||||
var notifyAboutUpdates: Boolean
|
||||
get() { mNotifyAboutUpdates = mNotifyAboutUpdates ?: config.values.get("notifyAboutUpdates", true); return mNotifyAboutUpdates ?: true }
|
||||
set(value) { config.set("notifyAboutUpdates", value); mNotifyAboutUpdates = value }
|
||||
// Register Availability
|
||||
private var registerAvailabilityMap by base.config<Map<String, RegisterAvailabilityStatus>>("registerAvailability") { mapOf() }
|
||||
private var registerAvailabilityFlavor by base.config<String?>(null)
|
||||
|
||||
private var mLastAppSync: Long? = null
|
||||
var lastAppSync: Long
|
||||
get() { mLastAppSync = mLastAppSync ?: config.values.get("lastAppSync", 0L); return mLastAppSync ?: 0L }
|
||||
set(value) { config.set("lastAppSync", value); mLastAppSync = value }
|
||||
|
||||
/* ____ _ _ _
|
||||
/ __ \ (_) | | | |
|
||||
| | | |_ _ _ ___| |_ | |__ ___ _ _ _ __ ___
|
||||
| | | | | | | |/ _ \ __| | '_ \ / _ \| | | | '__/ __|
|
||||
| |__| | |_| | | __/ |_ | | | | (_) | |_| | | \__ \
|
||||
\___\_\\__,_|_|\___|\__| |_| |_|\___/ \__,_|_| |__*/
|
||||
private var mQuietHoursEnabled: Boolean? = null
|
||||
var quietHoursEnabled: Boolean
|
||||
get() { mQuietHoursEnabled = mQuietHoursEnabled ?: config.values.get("quietHoursEnabled", false); return mQuietHoursEnabled ?: false }
|
||||
set(value) { config.set("quietHoursEnabled", value); mQuietHoursEnabled = value }
|
||||
|
||||
private var mQuietHoursStart: Time? = null
|
||||
var quietHoursStart: Time?
|
||||
get() { mQuietHoursStart = mQuietHoursStart ?: config.values.get("quietHoursStart", null as Time?); return mQuietHoursStart }
|
||||
set(value) { config.set("quietHoursStart", value); mQuietHoursStart = value }
|
||||
|
||||
private var mQuietHoursEnd: Time? = null
|
||||
var quietHoursEnd: Time?
|
||||
get() { mQuietHoursEnd = mQuietHoursEnd ?: config.values.get("quietHoursEnd", null as Time?); return mQuietHoursEnd }
|
||||
set(value) { config.set("quietHoursEnd", value); mQuietHoursEnd = value }
|
||||
|
||||
private var mQuietDuringLessons: Boolean? = null
|
||||
var quietDuringLessons: Boolean
|
||||
get() { mQuietDuringLessons = mQuietDuringLessons ?: config.values.get("quietDuringLessons", false); return mQuietDuringLessons ?: false }
|
||||
set(value) { config.set("quietDuringLessons", value); mQuietDuringLessons = value }
|
||||
|
||||
/* ______ _____ __ __ _______ _
|
||||
| ____/ ____| \/ | |__ __| | |
|
||||
| |__ | | | \ / | | | ___ | | _____ _ __ ___
|
||||
| __|| | | |\/| | | |/ _ \| |/ / _ \ '_ \/ __|
|
||||
| | | |____| | | | | | (_) | < __/ | | \__ \
|
||||
|_| \_____|_| |_| |_|\___/|_|\_\___|_| |_|__*/
|
||||
private var mTokenApp: String? = null
|
||||
var tokenApp: String?
|
||||
get() { mTokenApp = mTokenApp ?: config.values.get("tokenApp", null as String?); return mTokenApp }
|
||||
set(value) { config.set("tokenApp", value); mTokenApp = value }
|
||||
private var mTokenMobidziennik: String? = null
|
||||
var tokenMobidziennik: String?
|
||||
get() { mTokenMobidziennik = mTokenMobidziennik ?: config.values.get("tokenMobidziennik", null as String?); return mTokenMobidziennik }
|
||||
set(value) { config.set("tokenMobidziennik", value); mTokenMobidziennik = value }
|
||||
private var mTokenLibrus: String? = null
|
||||
var tokenLibrus: String?
|
||||
get() { mTokenLibrus = mTokenLibrus ?: config.values.get("tokenLibrus", null as String?); return mTokenLibrus }
|
||||
set(value) { config.set("tokenLibrus", value); mTokenLibrus = value }
|
||||
private var mTokenVulcan: String? = null
|
||||
var tokenVulcan: String?
|
||||
get() { mTokenVulcan = mTokenVulcan ?: config.values.get("tokenVulcan", null as String?); return mTokenVulcan }
|
||||
set(value) { config.set("tokenVulcan", value); mTokenVulcan = value }
|
||||
private var mTokenVulcanHebe: String? = null
|
||||
var tokenVulcanHebe: String?
|
||||
get() { mTokenVulcanHebe = mTokenVulcanHebe ?: config.values.get("tokenVulcanHebe", null as String?); return mTokenVulcanHebe }
|
||||
set(value) { config.set("tokenVulcanHebe", value); mTokenVulcanHebe = value }
|
||||
|
||||
private var mTokenMobidziennikList: List<Int>? = null
|
||||
var tokenMobidziennikList: List<Int>
|
||||
get() { mTokenMobidziennikList = mTokenMobidziennikList ?: config.values.getIntList("tokenMobidziennikList", listOf()); return mTokenMobidziennikList ?: listOf() }
|
||||
set(value) { config.set("tokenMobidziennikList", value); mTokenMobidziennikList = value }
|
||||
private var mTokenLibrusList: List<Int>? = null
|
||||
var tokenLibrusList: List<Int>
|
||||
get() { mTokenLibrusList = mTokenLibrusList ?: config.values.getIntList("tokenLibrusList", listOf()); return mTokenLibrusList ?: listOf() }
|
||||
set(value) { config.set("tokenLibrusList", value); mTokenLibrusList = value }
|
||||
private var mTokenVulcanList: List<Int>? = null
|
||||
var tokenVulcanList: List<Int>
|
||||
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
|
||||
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
|
||||
private var mTokenVulcanHebeList: List<Int>? = null
|
||||
var tokenVulcanHebeList: List<Int>
|
||||
get() { mTokenVulcanHebeList = mTokenVulcanHebeList ?: config.values.getIntList("tokenVulcanHebeList", listOf()); return mTokenVulcanHebeList ?: listOf() }
|
||||
set(value) { config.set("tokenVulcanHebeList", value); mTokenVulcanHebeList = value }
|
||||
|
||||
private var mRegisterAvailability: Map<String, RegisterAvailabilityStatus>? = null
|
||||
var registerAvailability: Map<String, RegisterAvailabilityStatus>
|
||||
get() {
|
||||
val flavor = config.values.get("registerAvailabilityFlavor", null as String?)
|
||||
if (BuildConfig.FLAVOR != flavor)
|
||||
if (BuildConfig.FLAVOR != registerAvailabilityFlavor)
|
||||
return mapOf()
|
||||
|
||||
mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it ->
|
||||
gson.fromJson(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type)
|
||||
}
|
||||
return mRegisterAvailability ?: mapOf()
|
||||
return registerAvailabilityMap
|
||||
}
|
||||
set(value) {
|
||||
config.setMap("registerAvailability", value)
|
||||
config.set("registerAvailabilityFlavor", BuildConfig.FLAVOR)
|
||||
mRegisterAvailability = value
|
||||
registerAvailabilityMap = value
|
||||
registerAvailabilityFlavor = BuildConfig.FLAVOR
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,12 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigTimetable(private val config: Config) {
|
||||
private var mBellSyncMultiplier: Int? = null
|
||||
var bellSyncMultiplier: Int
|
||||
get() { mBellSyncMultiplier = mBellSyncMultiplier ?: config.values.get("bellSyncMultiplier", 0); return mBellSyncMultiplier ?: 0 }
|
||||
set(value) { config.set("bellSyncMultiplier", value); mBellSyncMultiplier = value }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigTimetable(base: Config) {
|
||||
|
||||
private var mBellSyncDiff: Time? = null
|
||||
var bellSyncDiff: Time?
|
||||
get() { mBellSyncDiff = mBellSyncDiff ?: config.values.get("bellSyncDiff", null as Time?); return mBellSyncDiff }
|
||||
set(value) { config.set("bellSyncDiff", value); mBellSyncDiff = value }
|
||||
|
||||
private var mCountInSeconds: Boolean? = null
|
||||
var countInSeconds: Boolean
|
||||
get() { mCountInSeconds = mCountInSeconds ?: config.values.get("countInSeconds", false); return mCountInSeconds ?: false }
|
||||
set(value) { config.set("countInSeconds", value); mCountInSeconds = value }
|
||||
}
|
||||
var bellSyncMultiplier by base.config<Int>(0)
|
||||
var bellSyncDiff by base.config<Time?>(null)
|
||||
var countInSeconds by base.config<Boolean>(false)
|
||||
}
|
||||
|
@ -4,60 +4,32 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.ext.asNavTargetOrNull
|
||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||
|
||||
class ConfigUI(private val config: Config) {
|
||||
private var mTheme: Int? = null
|
||||
var theme: Int
|
||||
get() { mTheme = mTheme ?: config.values.get("theme", 1); return mTheme ?: 1 }
|
||||
set(value) { config.set("theme", value); mTheme = value }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ConfigUI(base: Config) {
|
||||
|
||||
private var mLanguage: String? = null
|
||||
var language: String?
|
||||
get() { mLanguage = mLanguage ?: config.values.get("language", null as String?); return mLanguage }
|
||||
set(value) { config.set("language", value); mLanguage = value }
|
||||
var theme by base.config<Int>(1)
|
||||
var language by base.config<String?>(null)
|
||||
|
||||
private var mHeaderBackground: String? = null
|
||||
var headerBackground: String?
|
||||
get() { mHeaderBackground = mHeaderBackground ?: config.values.get("headerBg", null as String?); return mHeaderBackground }
|
||||
set(value) { config.set("headerBg", value); mHeaderBackground = value }
|
||||
var appBackground by base.config<String?>("appBg", null)
|
||||
var headerBackground by base.config<String?>("headerBg", null)
|
||||
|
||||
private var mAppBackground: String? = null
|
||||
var appBackground: String?
|
||||
get() { mAppBackground = mAppBackground ?: config.values.get("appBg", null as String?); return mAppBackground }
|
||||
set(value) { config.set("appBg", value); mAppBackground = value }
|
||||
var miniMenuVisible by base.config<Boolean>(false)
|
||||
var miniMenuButtons by base.config<Set<NavTarget>> {
|
||||
setOf(
|
||||
NavTarget.HOME,
|
||||
NavTarget.TIMETABLE,
|
||||
NavTarget.AGENDA,
|
||||
NavTarget.GRADES,
|
||||
NavTarget.MESSAGES,
|
||||
NavTarget.HOMEWORK,
|
||||
NavTarget.SETTINGS
|
||||
)
|
||||
}
|
||||
var openDrawerOnBackPressed by base.config<Boolean>(false)
|
||||
|
||||
private var mMiniMenuVisible: Boolean? = null
|
||||
var miniMenuVisible: Boolean
|
||||
get() { mMiniMenuVisible = mMiniMenuVisible ?: config.values.get("miniMenuVisible", false); return mMiniMenuVisible ?: false }
|
||||
set(value) { config.set("miniMenuVisible", value); mMiniMenuVisible = value }
|
||||
|
||||
private var mMiniMenuButtons: Set<NavTarget>? = null
|
||||
var miniMenuButtons: Set<NavTarget>
|
||||
get() { mMiniMenuButtons = mMiniMenuButtons ?: config.values.getIntList("miniMenuButtons", listOf())?.mapNotNull { it.asNavTargetOrNull() }?.toSet(); return mMiniMenuButtons ?: setOf() }
|
||||
set(value) { config.set("miniMenuButtons", value.map { it.id }); mMiniMenuButtons = value }
|
||||
|
||||
private var mOpenDrawerOnBackPressed: Boolean? = null
|
||||
var openDrawerOnBackPressed: Boolean
|
||||
get() { mOpenDrawerOnBackPressed = mOpenDrawerOnBackPressed ?: config.values.get("openDrawerOnBackPressed", false); return mOpenDrawerOnBackPressed ?: false }
|
||||
set(value) { config.set("openDrawerOnBackPressed", value); mOpenDrawerOnBackPressed = value }
|
||||
|
||||
private var mSnowfall: Boolean? = null
|
||||
var snowfall: Boolean
|
||||
get() { mSnowfall = mSnowfall ?: config.values.get("snowfall", false); return mSnowfall ?: false }
|
||||
set(value) { config.set("snowfall", value); mSnowfall = value }
|
||||
|
||||
private var mEggfall: Boolean? = null
|
||||
var eggfall: Boolean
|
||||
get() { mEggfall = mEggfall ?: config.values.get("eggfall", false); return mEggfall ?: false }
|
||||
set(value) { config.set("eggfall", value); mEggfall = value }
|
||||
|
||||
private var mBottomSheetOpened: Boolean? = null
|
||||
var bottomSheetOpened: Boolean
|
||||
get() { mBottomSheetOpened = mBottomSheetOpened ?: config.values.get("bottomSheetOpened", false); return mBottomSheetOpened ?: false }
|
||||
set(value) { config.set("bottomSheetOpened", value); mBottomSheetOpened = value }
|
||||
var bottomSheetOpened by base.config<Boolean>(false)
|
||||
var snowfall by base.config<Boolean>(false)
|
||||
var eggfall by base.config<Boolean>(false)
|
||||
}
|
||||
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2022-10-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.ext.*
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.WildcardType
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
private val gson = Gson()
|
||||
|
||||
inline fun <reified T> BaseConfig.config(name: String? = null, noinline default: () -> T) = ConfigDelegate(
|
||||
config = this,
|
||||
type = T::class.java,
|
||||
nullable = null is T,
|
||||
typeToken = object : TypeToken<T>() {},
|
||||
defaultFunc = default,
|
||||
defaultValue = null,
|
||||
fieldName = name,
|
||||
)
|
||||
|
||||
inline fun <reified T> BaseConfig.config(default: T) = ConfigDelegate(
|
||||
config = this,
|
||||
type = T::class.java,
|
||||
nullable = null is T,
|
||||
typeToken = object : TypeToken<T>() {},
|
||||
defaultFunc = null,
|
||||
defaultValue = default,
|
||||
fieldName = null,
|
||||
)
|
||||
|
||||
inline fun <reified T> BaseConfig.config(name: String? = null, default: T) = ConfigDelegate(
|
||||
config = this,
|
||||
type = T::class.java,
|
||||
nullable = null is T,
|
||||
typeToken = object : TypeToken<T>() {},
|
||||
defaultFunc = null,
|
||||
defaultValue = default,
|
||||
fieldName = name,
|
||||
)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class ConfigDelegate<T>(
|
||||
private val config: BaseConfig,
|
||||
private val type: Class<T>,
|
||||
private val nullable: Boolean,
|
||||
private val typeToken: TypeToken<T>,
|
||||
private val defaultFunc: (() -> T)?,
|
||||
private val defaultValue: T?,
|
||||
private val fieldName: String?,
|
||||
) {
|
||||
private var value: T? = null
|
||||
private var isInitialized = false
|
||||
|
||||
private fun getDefault(): T = when {
|
||||
defaultFunc != null -> defaultFunc.invoke()
|
||||
else -> defaultValue as T
|
||||
}
|
||||
|
||||
private fun getGenericType(index: Int = 0): Class<*> {
|
||||
val parameterizedType = typeToken.type as ParameterizedType
|
||||
val typeArgument = parameterizedType.actualTypeArguments[index] as WildcardType
|
||||
return typeArgument.upperBounds[0] as Class<*>
|
||||
}
|
||||
|
||||
operator fun setValue(_thisRef: Any, property: KProperty<*>, newValue: T) {
|
||||
value = newValue
|
||||
isInitialized = true
|
||||
config.set(fieldName ?: property.name, serialize(newValue)?.toString())
|
||||
}
|
||||
|
||||
operator fun getValue(_thisRef: Any, property: KProperty<*>): T {
|
||||
if (isInitialized)
|
||||
return value as T
|
||||
val key = fieldName ?: property.name
|
||||
|
||||
if (key !in config.values) {
|
||||
value = getDefault()
|
||||
isInitialized = true
|
||||
return value as T
|
||||
}
|
||||
val str = config.values[key]
|
||||
|
||||
value = if (str == null && nullable)
|
||||
null as T
|
||||
else if (str == null)
|
||||
getDefault()
|
||||
else
|
||||
deserialize(str)
|
||||
|
||||
isInitialized = true
|
||||
return value as T
|
||||
}
|
||||
|
||||
private fun <I> serialize(value: I?, serializeObjects: Boolean = true): Any? {
|
||||
if (value == null)
|
||||
return null
|
||||
|
||||
return when (value) {
|
||||
is String -> value
|
||||
is Date -> value.stringY_m_d
|
||||
is Time -> value.stringValue
|
||||
is JsonObject -> value
|
||||
is JsonArray -> value
|
||||
// primitives
|
||||
is Number -> value
|
||||
is Boolean -> value
|
||||
// enums, maps & collections
|
||||
is Enum<*> -> value.toInt()
|
||||
is Collection<*> -> JsonArray(value.map {
|
||||
if (it is Number || it is Boolean) it else serialize(it, serializeObjects = false)
|
||||
})
|
||||
is Map<*, *> -> gson.toJson(value.mapValues { (_, it) ->
|
||||
if (it is Number || it is Boolean) it else serialize(it, serializeObjects = false)
|
||||
})
|
||||
// objects or else
|
||||
else -> if (serializeObjects) gson.toJson(value) else value
|
||||
}
|
||||
}
|
||||
|
||||
private fun <I> deserialize(value: String?, type: Class<*> = this.type): I? {
|
||||
if (value == null)
|
||||
return null
|
||||
|
||||
@Suppress("TYPE_MISMATCH_WARNING")
|
||||
return when (type) {
|
||||
String::class.java -> value
|
||||
Date::class.java -> Date.fromY_m_d(value)
|
||||
Time::class.java -> Time.fromHms(value)
|
||||
JsonObject::class.java -> value.toJsonObject()
|
||||
JsonArray::class.java -> value.toJsonArray()
|
||||
// primitives
|
||||
java.lang.Integer::class.java -> value.toIntOrNull()
|
||||
java.lang.Boolean::class.java -> value.toBooleanStrictOrNull()
|
||||
java.lang.Long::class.java -> value.toLongOrNull()
|
||||
java.lang.Float::class.java -> value.toFloatOrNull()
|
||||
// enums, maps & collections
|
||||
else -> when {
|
||||
Enum::class.java.isAssignableFrom(type) -> value.toIntOrNull()?.toEnum(type) as Enum<*>
|
||||
Collection::class.java.isAssignableFrom(type) -> {
|
||||
val array = value.toJsonArray()
|
||||
val genericType = getGenericType()
|
||||
val list = array?.map {
|
||||
val str = if (it.isJsonPrimitive) it.asString else it.toString()
|
||||
deserialize<Any>(str, genericType)
|
||||
}
|
||||
when {
|
||||
List::class.java.isAssignableFrom(type) -> list
|
||||
Set::class.java.isAssignableFrom(type) -> list?.toSet()
|
||||
else -> list?.toTypedArray()
|
||||
}
|
||||
}
|
||||
Map::class.java.isAssignableFrom(type) -> {
|
||||
val obj = value.toJsonObject()
|
||||
val genericType = getGenericType(index = 1)
|
||||
val map = obj?.entrySet()?.associate { (key, it) ->
|
||||
val str = if (it.isJsonPrimitive) it.asString else it.toString()
|
||||
key to deserialize<Any>(str, genericType)
|
||||
}
|
||||
map
|
||||
}
|
||||
// objects or else
|
||||
else -> gson.fromJson(value, type)
|
||||
}
|
||||
} as? I
|
||||
}
|
||||
}
|
@ -4,29 +4,20 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.config.utils.ProfileConfigMigration
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.config.utils.toHashMap
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEntry>) : CoroutineScope, AbstractConfig {
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfig(
|
||||
db: AppDb,
|
||||
profileId: Int,
|
||||
entries: List<ConfigEntry>?,
|
||||
) : BaseConfig(db, profileId, entries) {
|
||||
companion object {
|
||||
const val DATA_VERSION = 3
|
||||
const val DATA_VERSION = 4
|
||||
}
|
||||
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Default
|
||||
|
||||
val values: HashMap<String, String?> = hashMapOf()
|
||||
|
||||
val grades by lazy { ProfileConfigGrades(this) }
|
||||
val ui by lazy { ProfileConfigUI(this) }
|
||||
val sync by lazy { ProfileConfigSync(this) }
|
||||
@ -35,26 +26,11 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
|
||||
val timetable by lazy { ConfigTimetable(this) }
|
||||
val grades by lazy { ConfigGrades(this) }*/
|
||||
|
||||
private var mDataVersion: Int? = null
|
||||
var dataVersion: Int
|
||||
get() { mDataVersion = mDataVersion ?: values.get("dataVersion", 0); return mDataVersion ?: 0 }
|
||||
set(value) { set("dataVersion", value); mDataVersion = value }
|
||||
|
||||
private var mHash: String? = null
|
||||
var hash: String
|
||||
get() { mHash = mHash ?: values.get("hash", ""); return mHash ?: "" }
|
||||
set(value) { set("hash", value); mHash = value }
|
||||
var dataVersion by config<Int>(0)
|
||||
var hash by config<String>("")
|
||||
|
||||
init {
|
||||
rawEntries.toHashMap(profileId, values)
|
||||
if (dataVersion < DATA_VERSION)
|
||||
ProfileConfigMigration(this)
|
||||
}
|
||||
|
||||
override fun set(key: String, value: String?) {
|
||||
values[key] = value
|
||||
launch {
|
||||
db.configDao().add(ConfigEntry(profileId, key, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,11 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigAttendance(base: ProfileConfig) {
|
||||
|
||||
class ProfileConfigAttendance(private val config: ProfileConfig) {
|
||||
private var mAttendancePageSelection: Int? = null
|
||||
var attendancePageSelection: Int
|
||||
get() { mAttendancePageSelection = mAttendancePageSelection ?: config.values.get("attendancePageSelection", 1); return mAttendancePageSelection ?: 1 }
|
||||
set(value) { config.set("attendancePageSelection", value); mAttendancePageSelection = value }
|
||||
|
||||
private var mUseSymbols: Boolean? = null
|
||||
var useSymbols: Boolean
|
||||
get() { mUseSymbols = mUseSymbols ?: config.values.get("useSymbols", false); return mUseSymbols ?: false }
|
||||
set(value) { config.set("useSymbols", value); mUseSymbols = value }
|
||||
|
||||
private var mGroupConsecutiveDays: Boolean? = null
|
||||
var groupConsecutiveDays: Boolean
|
||||
get() { mGroupConsecutiveDays = mGroupConsecutiveDays ?: config.values.get("groupConsecutiveDays", true); return mGroupConsecutiveDays ?: true }
|
||||
set(value) { config.set("groupConsecutiveDays", value); mGroupConsecutiveDays = value }
|
||||
|
||||
private var mShowPresenceInMonth: Boolean? = null
|
||||
var showPresenceInMonth: Boolean
|
||||
get() { mShowPresenceInMonth = mShowPresenceInMonth ?: config.values.get("showPresenceInMonth", false); return mShowPresenceInMonth ?: false }
|
||||
set(value) { config.set("showPresenceInMonth", value); mShowPresenceInMonth = value }
|
||||
var attendancePageSelection by base.config<Int>(1)
|
||||
var groupConsecutiveDays by base.config<Boolean>(true)
|
||||
var showPresenceInMonth by base.config<Boolean>(false)
|
||||
var useSymbols by base.config<Boolean>(false)
|
||||
}
|
||||
|
@ -4,54 +4,19 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.getFloat
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES
|
||||
|
||||
class ProfileConfigGrades(private val config: ProfileConfig) {
|
||||
private var mColorMode: Int? = null
|
||||
var colorMode: Int
|
||||
get() { mColorMode = mColorMode ?: config.values.get("gradesColorMode", COLOR_MODE_WEIGHTED); return mColorMode ?: COLOR_MODE_WEIGHTED }
|
||||
set(value) { config.set("gradesColorMode", value); mColorMode = value }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigGrades(base: ProfileConfig) {
|
||||
|
||||
private var mYearAverageMode: Int? = null
|
||||
var yearAverageMode: Int
|
||||
get() { mYearAverageMode = mYearAverageMode ?: config.values.get("yearAverageMode", YEAR_ALL_GRADES); return mYearAverageMode ?: YEAR_ALL_GRADES }
|
||||
set(value) { config.set("yearAverageMode", value); mYearAverageMode = value }
|
||||
|
||||
private var mHideImproved: Boolean? = null
|
||||
var hideImproved: Boolean
|
||||
get() { mHideImproved = mHideImproved ?: config.values.get("hideImproved", false); return mHideImproved ?: false }
|
||||
set(value) { config.set("hideImproved", value); mHideImproved = value }
|
||||
|
||||
private var mAverageWithoutWeight: Boolean? = null
|
||||
var averageWithoutWeight: Boolean
|
||||
get() { mAverageWithoutWeight = mAverageWithoutWeight ?: config.values.get("averageWithoutWeight", true); return mAverageWithoutWeight ?: true }
|
||||
set(value) { config.set("averageWithoutWeight", value); mAverageWithoutWeight = value }
|
||||
|
||||
private var mPlusValue: Float? = null
|
||||
var plusValue: Float?
|
||||
get() { mPlusValue = mPlusValue ?: config.values.getFloat("plusValue"); return mPlusValue }
|
||||
set(value) { config.set("plusValue", value); mPlusValue = value }
|
||||
private var mMinusValue: Float? = null
|
||||
var minusValue: Float?
|
||||
get() { mMinusValue = mMinusValue ?: config.values.getFloat("minusValue"); return mMinusValue }
|
||||
set(value) { config.set("minusValue", value); mMinusValue = value }
|
||||
|
||||
private var mDontCountEnabled: Boolean? = null
|
||||
var dontCountEnabled: Boolean
|
||||
get() { mDontCountEnabled = mDontCountEnabled ?: config.values.get("dontCountEnabled", false); return mDontCountEnabled ?: false }
|
||||
set(value) { config.set("dontCountEnabled", value); mDontCountEnabled = value }
|
||||
|
||||
private var mDontCountGrades: List<String>? = null
|
||||
var dontCountGrades: List<String>
|
||||
get() { mDontCountGrades = mDontCountGrades ?: config.values.get("dontCountGrades", listOf()); return mDontCountGrades ?: listOf() }
|
||||
set(value) { config.set("dontCountGrades", value); mDontCountGrades = value }
|
||||
|
||||
private var mHideSticksFromOld: Boolean? = null
|
||||
var hideSticksFromOld: Boolean
|
||||
get() { mHideSticksFromOld = mHideSticksFromOld ?: config.values.get("hideSticksFromOld", false); return mHideSticksFromOld ?: false }
|
||||
set(value) { config.set("hideSticksFromOld", value); mHideSticksFromOld = value }
|
||||
var averageWithoutWeight by base.config<Boolean>(true)
|
||||
var colorMode by base.config<Int>(COLOR_MODE_WEIGHTED)
|
||||
var dontCountEnabled by base.config<Boolean>(false)
|
||||
var dontCountGrades by base.config<List<String>> { listOf() }
|
||||
var hideImproved by base.config<Boolean>(false)
|
||||
var hideSticksFromOld by base.config<Boolean>(false)
|
||||
var minusValue by base.config<Float?>(null)
|
||||
var plusValue by base.config<Float?>(null)
|
||||
var yearAverageMode by base.config<Int>(YEAR_ALL_GRADES)
|
||||
}
|
||||
|
@ -4,14 +4,14 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
||||
import pl.szczodrzynski.edziennik.ext.asNotificationTypeOrNull
|
||||
|
||||
class ProfileConfigSync(private val config: ProfileConfig) {
|
||||
private var mNotificationFilter: Set<NotificationType>? = null
|
||||
var notificationFilter: Set<NotificationType>
|
||||
get() { mNotificationFilter = mNotificationFilter ?: config.values.getIntList("notificationFilter", listOf())?.mapNotNull { it.asNotificationTypeOrNull() }?.toSet(); return mNotificationFilter ?: setOf() }
|
||||
set(value) { config.set("notificationFilter", value.map { it.id }); mNotificationFilter = value }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigSync(base: ProfileConfig) {
|
||||
|
||||
var notificationFilter by base.config<Set<NotificationType>> {
|
||||
NotificationType.values()
|
||||
.filter { it.enabledByDefault == false }
|
||||
.toSet()
|
||||
}
|
||||
}
|
||||
|
@ -4,89 +4,29 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.config
|
||||
|
||||
import pl.szczodrzynski.edziennik.config.utils.get
|
||||
import pl.szczodrzynski.edziennik.config.utils.set
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
|
||||
class ProfileConfigUI(private val config: ProfileConfig) {
|
||||
private var mAgendaViewType: Int? = null
|
||||
var agendaViewType: Int
|
||||
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: AGENDA_DEFAULT }
|
||||
set(value) { config.set("agendaViewType", value); mAgendaViewType = value }
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
class ProfileConfigUI(base: ProfileConfig) {
|
||||
|
||||
private var mAgendaCompactMode: Boolean? = null
|
||||
var agendaCompactMode: Boolean
|
||||
get() { mAgendaCompactMode = mAgendaCompactMode ?: config.values.get("agendaCompactMode", false); return mAgendaCompactMode ?: false }
|
||||
set(value) { config.set("agendaCompactMode", value); mAgendaCompactMode = value }
|
||||
var agendaViewType by base.config<Int>(AGENDA_DEFAULT)
|
||||
var agendaCompactMode by base.config<Boolean>(false)
|
||||
var agendaGroupByType by base.config<Boolean>(false)
|
||||
var agendaLessonChanges by base.config<Boolean>(true)
|
||||
var agendaTeacherAbsence by base.config<Boolean>(true)
|
||||
var agendaElearningMark by base.config<Boolean>(false)
|
||||
var agendaElearningGroup by base.config<Boolean>(true)
|
||||
|
||||
private var mAgendaGroupByType: Boolean? = null
|
||||
var agendaGroupByType: Boolean
|
||||
get() { mAgendaGroupByType = mAgendaGroupByType ?: config.values.get("agendaGroupByType", false); return mAgendaGroupByType ?: false }
|
||||
set(value) { config.set("agendaGroupByType", value); mAgendaGroupByType = value }
|
||||
var homeCards by base.config<List<HomeCardModel>> { listOf() }
|
||||
|
||||
private var mAgendaLessonChanges: Boolean? = null
|
||||
var agendaLessonChanges: Boolean
|
||||
get() { mAgendaLessonChanges = mAgendaLessonChanges ?: config.values.get("agendaLessonChanges", true); return mAgendaLessonChanges ?: true }
|
||||
set(value) { config.set("agendaLessonChanges", value); mAgendaLessonChanges = value }
|
||||
var messagesGreetingOnCompose by base.config<Boolean>(true)
|
||||
var messagesGreetingOnReply by base.config<Boolean>(true)
|
||||
var messagesGreetingOnForward by base.config<Boolean>(false)
|
||||
var messagesGreetingText by base.config<String?>(null)
|
||||
|
||||
private var mAgendaTeacherAbsence: Boolean? = null
|
||||
var agendaTeacherAbsence: Boolean
|
||||
get() { mAgendaTeacherAbsence = mAgendaTeacherAbsence ?: config.values.get("agendaTeacherAbsence", true); return mAgendaTeacherAbsence ?: true }
|
||||
set(value) { config.set("agendaTeacherAbsence", value); mAgendaTeacherAbsence = value }
|
||||
|
||||
private var mAgendaElearningMark: Boolean? = null
|
||||
var agendaElearningMark: Boolean
|
||||
get() { mAgendaElearningMark = mAgendaElearningMark ?: config.values.get("agendaElearningMark", false); return mAgendaElearningMark ?: false }
|
||||
set(value) { config.set("agendaElearningMark", value); mAgendaElearningMark = value }
|
||||
|
||||
private var mAgendaElearningGroup: Boolean? = null
|
||||
var agendaElearningGroup: Boolean
|
||||
get() { mAgendaElearningGroup = mAgendaElearningGroup ?: config.values.get("agendaElearningGroup", true); return mAgendaElearningGroup ?: true }
|
||||
set(value) { config.set("agendaElearningGroup", value); mAgendaElearningGroup = value }
|
||||
|
||||
private var mHomeCards: List<HomeCardModel>? = null
|
||||
var homeCards: List<HomeCardModel>
|
||||
get() { mHomeCards = mHomeCards ?: config.values.get("homeCards", listOf(), HomeCardModel::class.java); return mHomeCards ?: listOf() }
|
||||
set(value) { config.set("homeCards", value); mHomeCards = value }
|
||||
|
||||
private var mMessagesGreetingOnCompose: Boolean? = null
|
||||
var messagesGreetingOnCompose: Boolean
|
||||
get() { mMessagesGreetingOnCompose = mMessagesGreetingOnCompose ?: config.values.get("messagesGreetingOnCompose", true); return mMessagesGreetingOnCompose ?: true }
|
||||
set(value) { config.set("messagesGreetingOnCompose", value); mMessagesGreetingOnCompose = value }
|
||||
|
||||
private var mMessagesGreetingOnReply: Boolean? = null
|
||||
var messagesGreetingOnReply: Boolean
|
||||
get() { mMessagesGreetingOnReply = mMessagesGreetingOnReply ?: config.values.get("messagesGreetingOnReply", true); return mMessagesGreetingOnReply ?: true }
|
||||
set(value) { config.set("messagesGreetingOnReply", value); mMessagesGreetingOnReply = value }
|
||||
|
||||
private var mMessagesGreetingOnForward: Boolean? = null
|
||||
var messagesGreetingOnForward: Boolean
|
||||
get() { mMessagesGreetingOnForward = mMessagesGreetingOnForward ?: config.values.get("messagesGreetingOnForward", false); return mMessagesGreetingOnForward ?: false }
|
||||
set(value) { config.set("messagesGreetingOnForward", value); mMessagesGreetingOnForward = value }
|
||||
|
||||
private var mMessagesGreetingText: String? = null
|
||||
var messagesGreetingText: String?
|
||||
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
||||
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
||||
|
||||
private var mTimetableShowAttendance: Boolean? = null
|
||||
var timetableShowAttendance: Boolean
|
||||
get() { mTimetableShowAttendance = mTimetableShowAttendance ?: config.values.get("timetableShowAttendance", true); return mTimetableShowAttendance ?: true }
|
||||
set(value) { config.set("timetableShowAttendance", value); mTimetableShowAttendance = value }
|
||||
|
||||
private var mTimetableShowEvents: Boolean? = null
|
||||
var timetableShowEvents: Boolean
|
||||
get() { mTimetableShowEvents = mTimetableShowEvents ?: config.values.get("timetableShowEvents", true); return mTimetableShowEvents ?: true }
|
||||
set(value) { config.set("timetableShowEvents", value); mTimetableShowEvents = value }
|
||||
|
||||
private var mTimetableTrimHourRange: Boolean? = null
|
||||
var timetableTrimHourRange: Boolean
|
||||
get() { mTimetableTrimHourRange = mTimetableTrimHourRange ?: config.values.get("timetableTrimHourRange", false); return mTimetableTrimHourRange ?: false }
|
||||
set(value) { config.set("timetableTrimHourRange", value); mTimetableTrimHourRange = value }
|
||||
|
||||
private var mTimetableColorSubjectName: Boolean? = null
|
||||
var timetableColorSubjectName: Boolean
|
||||
get() { mTimetableColorSubjectName = mTimetableColorSubjectName ?: config.values.get("timetableColorSubjectName", false); return mTimetableColorSubjectName ?: false }
|
||||
set(value) { config.set("timetableColorSubjectName", value); mTimetableColorSubjectName = value }
|
||||
var timetableShowAttendance by base.config<Boolean>(true)
|
||||
var timetableShowEvents by base.config<Boolean>(true)
|
||||
var timetableTrimHourRange by base.config<Boolean>(false)
|
||||
var timetableColorSubjectName by base.config<Boolean>(false)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ interface ConfigDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun addAll(list: List<ConfigEntry>)
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = -1")
|
||||
@Query("SELECT * FROM config")
|
||||
fun getAllNow(): List<ConfigEntry>
|
||||
|
||||
@Query("SELECT * FROM config WHERE profileId = :profileId")
|
||||
@ -25,4 +25,4 @@ interface ConfigDao {
|
||||
|
||||
@Query("DELETE FROM config WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
}
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.*
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import pl.szczodrzynski.edziennik.config.AbstractConfig
|
||||
import pl.szczodrzynski.edziennik.config.db.ConfigEntry
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
private val gson = Gson()
|
||||
|
||||
fun AbstractConfig.set(key: String, value: Int) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Boolean) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Long) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Float) {
|
||||
set(key, value.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Date?) {
|
||||
set(key, value?.stringY_m_d)
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Time?) {
|
||||
set(key, value?.stringValue)
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: JsonElement?) {
|
||||
set(key, value?.toString())
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: List<Any>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.set(key: String, value: Any?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setStringList(key: String, value: List<String>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setIntList(key: String, value: List<Int>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun AbstractConfig.setLongList(key: String, value: List<Long>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
fun <K, V> AbstractConfig.setMap(key: String, value: Map<K, V>?) {
|
||||
set(key, value?.let { gson.toJson(it) })
|
||||
}
|
||||
|
||||
fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
||||
return this[key] ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Boolean): Boolean {
|
||||
return this[key]?.toBoolean() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getBooleanOrNull(key: String): Boolean? {
|
||||
return this[key]?.toBooleanStrictOrNull()
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Int): Int {
|
||||
return this[key]?.toIntOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Long): Long {
|
||||
return this[key]?.toLongOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Float): Float {
|
||||
return this[key]?.toFloatOrNull() ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Date?): Date? {
|
||||
return this[key]?.let { Date.fromY_m_d(it) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: Time?): Time? {
|
||||
return this[key]?.let { Time.fromHms(it) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonObject?): JsonObject? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonObject } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.get(key: String, default: JsonArray?): JsonArray? {
|
||||
return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default
|
||||
}
|
||||
inline fun <reified T> HashMap<String, String?>.get(key: String, default: T?): T? {
|
||||
return this[key]?.let { Gson().fromJson(it, T::class.java) } ?: default
|
||||
}
|
||||
/* !!! cannot use mutable list here - modifying it will not update the DB */
|
||||
fun <T> HashMap<String, String?>.get(key: String, default: List<T>?, classOfT: Class<T>): List<T>? {
|
||||
return this[key]?.let { ConfigGsonUtils().deserializeList<T>(gson, it, classOfT) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getStringList(key: String, default: List<String>?): List<String>? {
|
||||
return this[key]?.let { gson.fromJson<List<String>>(it, object: TypeToken<List<String>>(){}.type) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getIntList(key: String, default: List<Int>?): List<Int>? {
|
||||
return this[key]?.let { gson.fromJson<List<Int>>(it, object: TypeToken<List<Int>>(){}.type) } ?: default
|
||||
}
|
||||
fun HashMap<String, String?>.getLongList(key: String, default: List<Long>?): List<Long>? {
|
||||
return this[key]?.let { gson.fromJson<List<Long>>(it, object: TypeToken<List<Long>>(){}.type) } ?: default
|
||||
}
|
||||
|
||||
fun HashMap<String, String?>.getFloat(key: String): Float? {
|
||||
return this[key]?.toFloatOrNull()
|
||||
}
|
||||
|
||||
fun List<ConfigEntry>.toHashMap(profileId: Int, map: HashMap<String, String?>) {
|
||||
map.clear()
|
||||
forEach {
|
||||
if (it.profileId == profileId)
|
||||
map[it.key] = it.value
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-2.
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.config.utils
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonParser
|
||||
import pl.szczodrzynski.edziennik.ext.getInt
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class ConfigGsonUtils {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> deserializeList(gson: Gson, str: String?, classOfT: Class<T>): List<T> {
|
||||
val json = JsonParser.parseString(str)
|
||||
val list: MutableList<T> = mutableListOf()
|
||||
if (!json.isJsonArray)
|
||||
return list
|
||||
|
||||
json.asJsonArray.forEach { e ->
|
||||
when (classOfT) {
|
||||
String::class.java -> {
|
||||
list += e.asString as T
|
||||
}
|
||||
HomeCardModel::class.java -> {
|
||||
val o = e.asJsonObject
|
||||
list += HomeCardModel(
|
||||
o.getInt("profileId", 0),
|
||||
o.getInt("cardId", 0)
|
||||
) as T
|
||||
}
|
||||
Time::class.java -> {
|
||||
val o = e.asJsonObject
|
||||
list += Time(
|
||||
o.getInt("hour", 0),
|
||||
o.getInt("minute", 0),
|
||||
o.getInt("second", 0)
|
||||
) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ package pl.szczodrzynski.edziennik.config.utils
|
||||
import android.content.Context
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.config.Config
|
||||
import pl.szczodrzynski.edziennik.ext.HOUR
|
||||
import pl.szczodrzynski.edziennik.ui.base.enums.NavTarget
|
||||
@ -25,72 +24,9 @@ class ConfigMigration(app: App, config: Config) {
|
||||
AppConfigMigrationV3(p, config)
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
appVersion = BuildConfig.VERSION_CODE
|
||||
loginFinished = false
|
||||
ui.language = null
|
||||
ui.theme = 1
|
||||
ui.appBackground = null
|
||||
ui.headerBackground = null
|
||||
ui.miniMenuVisible = false
|
||||
ui.miniMenuButtons = setOf(
|
||||
NavTarget.HOME,
|
||||
NavTarget.TIMETABLE,
|
||||
NavTarget.AGENDA,
|
||||
NavTarget.GRADES,
|
||||
NavTarget.MESSAGES,
|
||||
NavTarget.HOMEWORK,
|
||||
NavTarget.SETTINGS
|
||||
)
|
||||
sync.enabled = true
|
||||
sync.interval = 1* HOUR.toInt()
|
||||
sync.notifyAboutUpdates = true
|
||||
sync.onlyWifi = false
|
||||
sync.quietHoursEnabled = false
|
||||
sync.quietHoursStart = null
|
||||
sync.quietHoursEnd = null
|
||||
sync.quietDuringLessons = false
|
||||
sync.tokenApp = null
|
||||
sync.tokenMobidziennik = null
|
||||
sync.tokenMobidziennikList = listOf()
|
||||
sync.tokenLibrus = null
|
||||
sync.tokenLibrusList = listOf()
|
||||
sync.tokenVulcan = null
|
||||
sync.tokenVulcanList = listOf()
|
||||
timetable.bellSyncMultiplier = 0
|
||||
timetable.bellSyncDiff = null
|
||||
timetable.countInSeconds = false
|
||||
grades.orderBy = ORDER_BY_DATE_DESC
|
||||
|
||||
dataVersion = 2
|
||||
}
|
||||
|
||||
if (dataVersion < 3) {
|
||||
update = null
|
||||
privacyPolicyAccepted = false
|
||||
devMode = null
|
||||
devModePassword = null
|
||||
appInstalledTime = 0L
|
||||
appRateSnackbarTime = 0L
|
||||
|
||||
dataVersion = 3
|
||||
}
|
||||
|
||||
if (dataVersion < 10) {
|
||||
ui.openDrawerOnBackPressed = false
|
||||
ui.snowfall = false
|
||||
ui.bottomSheetOpened = false
|
||||
sync.dontShowAppManagerDialog = false
|
||||
sync.webPushEnabled = true
|
||||
sync.lastAppSync = 0L
|
||||
|
||||
|
||||
dataVersion = 10
|
||||
}
|
||||
|
||||
if (dataVersion < 11) {
|
||||
val startMillis = config.values.get("quietHoursStart", 0L)
|
||||
val endMillis = config.values.get("quietHoursEnd", 0L)
|
||||
val startMillis = config.values["quietHoursStart"]?.toLongOrNull() ?: 0L
|
||||
val endMillis = config.values["quietHoursEnd"]?.toLongOrNull() ?: 0L
|
||||
if (startMillis > 0) {
|
||||
try {
|
||||
sync.quietHoursStart = Time.fromMillis(abs(startMillis))
|
||||
|
@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.config.utils
|
||||
import pl.szczodrzynski.edziennik.config.ProfileConfig
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.NotificationType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.SchoolType
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardModel
|
||||
import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED
|
||||
@ -15,21 +16,6 @@ import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_AL
|
||||
class ProfileConfigMigration(config: ProfileConfig) {
|
||||
init { config.apply {
|
||||
|
||||
if (dataVersion < 1) {
|
||||
grades.colorMode = COLOR_MODE_WEIGHTED
|
||||
grades.yearAverageMode = YEAR_ALL_GRADES
|
||||
grades.hideImproved = false
|
||||
grades.averageWithoutWeight = true
|
||||
grades.plusValue = null
|
||||
grades.minusValue = null
|
||||
grades.dontCountEnabled = false
|
||||
grades.dontCountGrades = listOf()
|
||||
ui.agendaViewType = AGENDA_DEFAULT
|
||||
// no migration for ui.homeCards
|
||||
|
||||
dataVersion = 1
|
||||
}
|
||||
|
||||
if (dataVersion < 2) {
|
||||
sync.notificationFilter = sync.notificationFilter + NotificationType.TEACHER_ABSENCE
|
||||
|
||||
@ -38,12 +24,24 @@ class ProfileConfigMigration(config: ProfileConfig) {
|
||||
|
||||
if (dataVersion < 3) {
|
||||
if (ui.homeCards.isNotEmpty()) {
|
||||
ui.homeCards = ui.homeCards.toMutableList().also {
|
||||
it.add(HomeCardModel(config.profileId, HomeCard.CARD_NOTES))
|
||||
}
|
||||
ui.homeCards = ui.homeCards + HomeCardModel(
|
||||
profileId = config.profileId ?: -1,
|
||||
cardId = HomeCard.CARD_NOTES,
|
||||
)
|
||||
}
|
||||
|
||||
dataVersion = 3
|
||||
}
|
||||
|
||||
if (dataVersion < 4) {
|
||||
// switch to new event types (USOS)
|
||||
dataVersion = 4
|
||||
|
||||
val profile = db.profileDao().getByIdNow(profileId ?: -1)
|
||||
if (profile?.loginStoreType?.schoolType == SchoolType.UNIVERSITY) {
|
||||
db.eventTypeDao().clear(profileId ?: -1)
|
||||
db.eventTypeDao().addDefaultTypes(profile)
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -3,15 +3,16 @@
|
||||
*/
|
||||
package pl.szczodrzynski.edziennik.data.db.dao
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Event.Companion.COLOR_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.config.AppData
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType.Companion.SOURCE_DEFAULT
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
|
||||
@Dao
|
||||
abstract class EventTypeDao {
|
||||
@ -36,17 +37,17 @@ abstract class EventTypeDao {
|
||||
@get:Query("SELECT * FROM eventTypes")
|
||||
abstract val allNow: List<EventType>
|
||||
|
||||
fun addDefaultTypes(context: Context, profileId: Int): List<EventType> {
|
||||
fun addDefaultTypes(profile: Profile): List<EventType> {
|
||||
val data = AppData.get(profile.loginStoreType)
|
||||
var order = 100
|
||||
val colorMap = EventType.getTypeColorMap()
|
||||
val typeList = EventType.getTypeNameMap().map { (id, name) ->
|
||||
val typeList = data.eventTypes.map {
|
||||
EventType(
|
||||
profileId = profileId,
|
||||
id = id,
|
||||
name = context.getString(name),
|
||||
color = colorMap[id] ?: COLOR_DEFAULT,
|
||||
profileId = profile.id,
|
||||
id = it.id.toLong(),
|
||||
name = it.name,
|
||||
color = Color.parseColor(it.color),
|
||||
order = order++,
|
||||
source = SOURCE_DEFAULT
|
||||
source = SOURCE_DEFAULT,
|
||||
)
|
||||
}
|
||||
addAll(typeList)
|
||||
|
@ -7,12 +7,13 @@ package pl.szczodrzynski.edziennik.data.db.enums
|
||||
enum class LoginType(
|
||||
val id: Int,
|
||||
val features: Set<FeatureType>,
|
||||
val schoolType: SchoolType = SchoolType.STANDARD,
|
||||
) {
|
||||
MOBIDZIENNIK(id = 1, features = FEATURES_MOBIDZIENNIK),
|
||||
LIBRUS(id = 2, features = FEATURES_LIBRUS),
|
||||
VULCAN(id = 4, features = FEATURES_VULCAN),
|
||||
PODLASIE(id = 6, features = FEATURES_PODLASIE),
|
||||
USOS(id = 7, features = FEATURES_USOS),
|
||||
USOS(id = 7, features = FEATURES_USOS, schoolType = SchoolType.UNIVERSITY),
|
||||
DEMO(id = 20, features = setOf()),
|
||||
TEMPLATE(id = 21, features = setOf()),
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2022-10-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.db.enums
|
||||
|
||||
enum class SchoolType {
|
||||
STANDARD,
|
||||
UNIVERSITY,
|
||||
}
|
@ -8,6 +8,8 @@ import android.util.LongSparseArray
|
||||
import androidx.core.util.forEach
|
||||
import com.google.android.material.datepicker.CalendarConstraints
|
||||
import com.google.gson.JsonElement
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.config.AppData
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||
@ -48,3 +50,6 @@ fun Profile.getSchoolYearConstrains(): CalendarConstraints {
|
||||
|
||||
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)
|
||||
|
@ -46,6 +46,7 @@ inline fun <reified E : Enum<E>> JsonObject?.getEnum(key: String) = this?.getInt
|
||||
fun JsonObject.putEnum(key: String, value: Enum<*>) = addProperty(key, value.toInt())
|
||||
|
||||
fun String.toJsonObject(): JsonObject? = try { JsonParser.parseString(this).asJsonObject } catch (ignore: Exception) { null }
|
||||
fun String.toJsonArray(): JsonArray? = try { JsonParser.parseString(this).asJsonArray } catch (ignore: Exception) { null }
|
||||
|
||||
operator fun JsonObject.set(key: String, value: JsonElement) = this.add(key, value)
|
||||
operator fun JsonObject.set(key: String, value: Boolean) = this.addProperty(key, value)
|
||||
@ -86,7 +87,9 @@ fun JsonObject.toBundle(): Bundle {
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonArray(vararg properties: Any?): JsonArray {
|
||||
fun JsonArray(vararg properties: Any?) = JsonArray(properties.toList())
|
||||
|
||||
fun JsonArray(properties: Collection<Any?>): JsonArray {
|
||||
return JsonArray().apply {
|
||||
for (property in properties) {
|
||||
when (property) {
|
||||
@ -112,3 +115,20 @@ operator fun JsonArray.plusAssign(o: String) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: Char) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: Number) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: Boolean) = this.add(o)
|
||||
|
||||
fun JsonObject.mergeWith(other: JsonObject): JsonObject {
|
||||
for ((key, value) in other.entrySet()) {
|
||||
when (value) {
|
||||
is JsonObject -> when {
|
||||
this.has(key) -> this.getJsonObject(key)?.mergeWith(value)
|
||||
else -> this.add(key, value)
|
||||
}
|
||||
is JsonArray -> when {
|
||||
this.has(key) -> this.getJsonArray(key)?.addAll(value)
|
||||
else -> this.add(key, value)
|
||||
}
|
||||
else -> this.add(key, value)
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
@ -72,3 +72,8 @@ fun pendingIntentFlag(): Int {
|
||||
return PendingIntent.FLAG_IMMUTABLE
|
||||
return 0
|
||||
}
|
||||
|
||||
fun Int?.takeValue() = if (this == -1) null else this
|
||||
fun Int?.takePositive() = if (this == -1 || this == 0) null else this
|
||||
|
||||
fun Any?.ignore() = Unit
|
||||
|
@ -22,7 +22,6 @@ import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.MetadataType
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding
|
||||
@ -33,7 +32,6 @@ import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class AgendaFragment : Fragment(), CoroutineScope {
|
||||
@ -144,7 +142,7 @@ class AgendaFragment : Fragment(), CoroutineScope {
|
||||
}
|
||||
val defaultEventTypes = EventType.getTypeColorMap().keys
|
||||
if (!eventTypes.containsAll(defaultEventTypes)) {
|
||||
app.db.eventTypeDao().addDefaultTypes(activity, app.profileId)
|
||||
app.db.eventTypeDao().addDefaultTypes(app.profile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class AnnouncementsFragment extends Fragment {
|
||||
if (app.getProfile().getLoginStoreType() == LoginType.LIBRUS) {
|
||||
EdziennikTask.Companion.announcementsRead(App.Companion.getProfileId()).enqueue(requireContext());
|
||||
} else {
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), MetadataType.ANNOUNCEMENT, true));
|
||||
AsyncTask.execute(() -> App.Companion.getDb().metadataDao().setAllSeen(App.Companion.getProfileId(), MetadataType.ANNOUNCEMENT, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
})
|
||||
@ -103,7 +103,7 @@ public class AnnouncementsFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
app.db.announcementDao().getAll(App.Companion.getProfileId()).observe(getViewLifecycleOwner(), announcements -> {
|
||||
app.getDb().announcementDao().getAll(App.Companion.getProfileId()).observe(getViewLifecycleOwner(), announcements -> {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
@ -174,7 +174,7 @@ public class AnnouncementsFragment extends Fragment {
|
||||
b.text.setText(announcement.getTeacherName() +"\n\n"+ (announcement.getStartDate() != null ? announcement.getStartDate().getFormattedString() : "-") + (announcement.getEndDate() != null ? " do " + announcement.getEndDate().getFormattedString() : "")+"\n\n" +announcement.getText());
|
||||
if (!announcement.getSeen() && app.getProfile().getLoginStoreType() != LoginType.LIBRUS) {
|
||||
announcement.setSeen(true);
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setSeen(App.Companion.getProfileId(), announcement, true));
|
||||
AsyncTask.execute(() -> App.Companion.getDb().metadataDao().setSeen(App.Companion.getProfileId(), announcement, true));
|
||||
if (recyclerView.getAdapter() != null)
|
||||
recyclerView.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class BehaviourFragment extends Fragment {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), MetadataType.NOTICE, true));
|
||||
AsyncTask.execute(() -> App.Companion.getDb().metadataDao().setAllSeen(App.Companion.getProfileId(), MetadataType.NOTICE, true));
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
);
|
||||
@ -111,7 +111,7 @@ public class BehaviourFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
app.db.noticeDao().getAll(App.Companion.getProfileId()).observe(getViewLifecycleOwner(), notices -> {
|
||||
app.getDb().noticeDao().getAll(App.Companion.getProfileId()).observe(getViewLifecycleOwner(), notices -> {
|
||||
if (app == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
|
@ -19,7 +19,6 @@ import eu.szkolny.font.SzkolnyFont
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.data.db.full.NoticeFull
|
||||
import pl.szczodrzynski.edziennik.utils.BetterLink
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.bs
|
||||
@ -40,7 +39,7 @@ class NoticesAdapter//getting the context and product list with constructor
|
||||
|
||||
val notice = noticeList[position]
|
||||
|
||||
if (app.profile.loginStoreType == LoginType.MOBIDZIENNIK && false) {
|
||||
if (app.data.uiConfig.enableNoticePoints && false) {
|
||||
holder.noticesItemReason.text = bs(null, notice.category, "\n") + notice.text
|
||||
holder.noticesItemTeacherName.text = app.getString(R.string.notices_points_format, notice.teacherName, if (notice.points ?: 0f > 0) "+" + notice.points else notice.points)
|
||||
} else {
|
||||
|
@ -26,7 +26,6 @@ import pl.szczodrzynski.edziennik.BuildConfig
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeBinding
|
||||
import pl.szczodrzynski.edziennik.ext.hasUIFeature
|
||||
import pl.szczodrzynski.edziennik.ext.onClick
|
||||
@ -127,7 +126,7 @@ class HomeFragment : Fragment(), CoroutineScope {
|
||||
.withOnClickListener(OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
launch { withContext(Dispatchers.Default) {
|
||||
if (app.profile.loginStoreType != LoginType.LIBRUS) {
|
||||
if (!app.data.uiConfig.enableMarkAsReadAnnouncements) {
|
||||
app.db.metadataDao().setAllSeenExceptMessagesAndAnnouncements(App.profileId, true)
|
||||
} else {
|
||||
app.db.metadataDao().setAllSeenExceptMessages(App.profileId, true)
|
||||
|
@ -11,14 +11,13 @@ import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.Navigation
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.config.AppData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskAllFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
|
||||
@ -29,6 +28,7 @@ import pl.szczodrzynski.edziennik.databinding.LoginSyncFragmentBinding
|
||||
import pl.szczodrzynski.edziennik.ext.Bundle
|
||||
import pl.szczodrzynski.edziennik.ext.asBoldSpannable
|
||||
import pl.szczodrzynski.edziennik.ext.concat
|
||||
import pl.szczodrzynski.edziennik.ext.ignore
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -56,7 +56,7 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) = launch {
|
||||
|
||||
EventBus.getDefault().removeStickyEvent(ApiTaskAllFinishedEvent::class.java)
|
||||
EventBus.getDefault().removeStickyEvent(ApiTaskErrorEvent::class.java)
|
||||
@ -64,26 +64,34 @@ class LoginSyncFragment : Fragment(), CoroutineScope {
|
||||
val profiles = activity.profiles.filter { it.isSelected }.map { it.profile }
|
||||
val loginStores = activity.loginStores.filter { store -> profiles.any { it.loginStoreId == store.id } }
|
||||
|
||||
val registrationAllowed = arguments?.getBoolean("registrationAllowed") ?: false
|
||||
profiles.forEach {
|
||||
it.registration = if (registrationAllowed)
|
||||
Profile.REGISTRATION_ENABLED
|
||||
else
|
||||
Profile.REGISTRATION_DISABLED
|
||||
withContext(Dispatchers.IO) {
|
||||
val registrationAllowed = arguments?.getBoolean("registrationAllowed") ?: false
|
||||
profiles.forEach {
|
||||
it.registration = if (registrationAllowed)
|
||||
Profile.REGISTRATION_ENABLED
|
||||
else
|
||||
Profile.REGISTRATION_DISABLED
|
||||
|
||||
app.db.eventTypeDao().addDefaultTypes(activity, it.id)
|
||||
val data = AppData.get(it.loginStoreType)
|
||||
val config = app.config.getFor(it.id)
|
||||
for ((key, value) in data.configOverrides) {
|
||||
config.set(key, value)
|
||||
}
|
||||
|
||||
app.db.eventTypeDao().addDefaultTypes(it)
|
||||
}
|
||||
|
||||
app.db.profileDao().addAll(profiles)
|
||||
app.db.loginStoreDao().addAll(loginStores)
|
||||
}
|
||||
|
||||
app.db.profileDao().addAll(profiles)
|
||||
app.db.loginStoreDao().addAll(loginStores)
|
||||
|
||||
finishArguments = Bundle(
|
||||
"firstProfileId" to profiles.firstOrNull()?.id
|
||||
)
|
||||
|
||||
val profileIds = profiles.map { it.id }.toSet()
|
||||
EdziennikTask.syncProfileList(profileIds).enqueue(activity)
|
||||
}
|
||||
}.ignore()
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncStartedEvent(event: ApiTaskStartedEvent) {
|
||||
|
@ -30,7 +30,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
|
||||
@ -76,8 +75,6 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
||||
|
||||
private lateinit var stylingConfig: StylingConfig
|
||||
private lateinit var uiConfig: UIConfig
|
||||
private val enableTextStyling
|
||||
get() = app.profile.loginStoreType != LoginType.LIBRUS
|
||||
private var changedRecipients = false
|
||||
private var changedSubject = false
|
||||
private var changedBody = false
|
||||
@ -154,14 +151,14 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
||||
}
|
||||
|
||||
private fun getMessageBody(): String {
|
||||
return if (enableTextStyling)
|
||||
return if (app.data.messagesConfig.textStyling)
|
||||
textStylingManager.getHtmlText(stylingConfig)
|
||||
else
|
||||
b.text.text?.toString() ?: ""
|
||||
}
|
||||
|
||||
private fun getRecipientList() {
|
||||
if (System.currentTimeMillis() - app.profile.lastReceiversSync > 1 * DAY * 1000 && app.profile.loginStoreType != LoginType.VULCAN) {
|
||||
if (app.data.messagesConfig.syncRecipientList && System.currentTimeMillis() - app.profile.lastReceiversSync > 1 * DAY * 1000) {
|
||||
activity.snackbar("Pobieranie listy odbiorców...")
|
||||
EdziennikTask.recipientListGet(App.profileId).enqueue(activity)
|
||||
}
|
||||
@ -262,8 +259,8 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
||||
},
|
||||
)
|
||||
|
||||
b.fontStyle.root.isVisible = enableTextStyling
|
||||
if (enableTextStyling) {
|
||||
b.fontStyle.root.isVisible = app.data.messagesConfig.textStyling
|
||||
if (app.data.messagesConfig.textStyling) {
|
||||
textStylingManager.attach(stylingConfig)
|
||||
b.fontStyle.styles.addOnButtonCheckedListener { _, _, _ ->
|
||||
changedBody = true
|
||||
@ -374,7 +371,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
||||
else -> b.text.requestFocus()
|
||||
}
|
||||
|
||||
if (!enableTextStyling)
|
||||
if (!app.data.messagesConfig.textStyling)
|
||||
b.text.setText(b.text.text?.toString())
|
||||
b.text.setSelection(0)
|
||||
(b.root as? ScrollView)?.smoothScrollTo(0, 0)
|
||||
|
@ -188,7 +188,7 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
}
|
||||
}
|
||||
|
||||
if (app.profile.loginStoreType == LoginType.VULCAN) {
|
||||
if (app.data.messagesConfig.needsReadStatus) {
|
||||
// vulcan: change message status or download attachments
|
||||
if ((message.isReceived || message.isDeleted) && !message.seen || message.attachmentIds == null) {
|
||||
EdziennikTask.messageGet(App.profileId, message).enqueue(activity)
|
||||
|
@ -83,7 +83,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
||||
startHour = startHour,
|
||||
endHour = endHour,
|
||||
dividerHeight = 1.dp,
|
||||
halfHourHeight = if (app.profile.loginStoreType == LoginType.USOS) 45.dp else 60.dp,
|
||||
halfHourHeight = app.data.uiConfig.lessonHeight.dp,
|
||||
hourDividerColor = R.attr.hourDividerColor.resolveAttr(context),
|
||||
halfHourDividerColor = R.attr.halfHourDividerColor.resolveAttr(context),
|
||||
hourLabelWidth = 40.dp,
|
||||
|
@ -37,7 +37,8 @@ class EventTypeDropdown : TextInputDropDown {
|
||||
var types = db.eventTypeDao().getAllNow(profileId)
|
||||
|
||||
if (types.none { it.id in -1L..10L }) {
|
||||
types = db.eventTypeDao().addDefaultTypes(context, profileId)
|
||||
val profile = db.profileDao().getByIdNow(profileId) ?: return@withContext listOf()
|
||||
types = db.eventTypeDao().addDefaultTypes(profile)
|
||||
}
|
||||
|
||||
list += types.map {
|
||||
|
@ -85,7 +85,7 @@ public class WidgetConfigActivity extends Activity {
|
||||
opacity = 0.8f;
|
||||
|
||||
AsyncTask.execute(() -> {
|
||||
profileList = App.db.profileDao().getAllNow();
|
||||
profileList = App.Companion.getDb().profileDao().getAllNow();
|
||||
profileList = filterOutArchived(profileList);
|
||||
|
||||
if (widgetType == WIDGET_NOTIFICATIONS)
|
||||
|
@ -25,7 +25,9 @@ import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
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.edziennik.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson.Companion.TYPE_NO_LESSONS
|
||||
@ -393,7 +395,7 @@ class WidgetTimetableProvider : AppWidgetProvider() {
|
||||
headerIntent.putExtra("profileId", it)
|
||||
}
|
||||
displayingDate?.let {
|
||||
headerIntent.putExtra("timetableDate", it.value)
|
||||
headerIntent.putExtra("timetableDate", it.stringY_m_d)
|
||||
}
|
||||
}
|
||||
headerIntent.putExtras("fragmentId" to NavTarget.TIMETABLE)
|
||||
|
176
app/src/main/res/raw/app_data.json
Normal file
176
app/src/main/res/raw/app_data.json
Normal file
@ -0,0 +1,176 @@
|
||||
{
|
||||
"base": {
|
||||
"messagesConfig": {
|
||||
"subjectLength": null,
|
||||
"bodyLength": null,
|
||||
"textStyling": true,
|
||||
"syncRecipientList": true,
|
||||
"htmlMode": "ORIGINAL",
|
||||
"needsReadStatus": false
|
||||
},
|
||||
"uiConfig": {
|
||||
"lessonHeight": 60,
|
||||
"enableMarkAsReadAnnouncements": true,
|
||||
"enableNoticePoints": false
|
||||
},
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": -5,
|
||||
"color": "#f57f17",
|
||||
"name": "lekcja online"
|
||||
},
|
||||
{
|
||||
"id": -1,
|
||||
"color": "#795548",
|
||||
"name": "zadanie domowe"
|
||||
},
|
||||
{
|
||||
"id": 0,
|
||||
"color": "#ffc107",
|
||||
"name": "inny"
|
||||
}
|
||||
]
|
||||
},
|
||||
"standard": {
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": 1,
|
||||
"color": "#f44336",
|
||||
"name": "sprawdzian"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"color": "#76ff03",
|
||||
"name": "kartkówka"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"color": "#4050b5",
|
||||
"name": "wypracowanie"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"color": "#673ab7",
|
||||
"name": "projekt"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"color": "#90caf9",
|
||||
"name": "zebranie z rodzicami"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"color": "#4caf50",
|
||||
"name": "wycieczka"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"color": "#ffeb3b",
|
||||
"name": "lektura"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"color": "#388e3c",
|
||||
"name": "wydarzenie klasowe"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"color": "#039be5",
|
||||
"name": "informacja"
|
||||
}
|
||||
]
|
||||
},
|
||||
"university": {
|
||||
"configOverrides": {
|
||||
"timetableColorSubjectName": true
|
||||
},
|
||||
"uiConfig": {
|
||||
"lessonHeight": 45
|
||||
},
|
||||
"eventTypes": [
|
||||
{
|
||||
"id": 1,
|
||||
"color": "#f44336",
|
||||
"name": "egzamin"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"color": "#e91e63",
|
||||
"name": "kolokwium"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"color": "#76ff03",
|
||||
"name": "kartkówka"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"color": "#ffeb3b",
|
||||
"name": "wejściówka"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"color": "#90caf9",
|
||||
"name": "zaliczenie"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"color": "#4050b5",
|
||||
"name": "zadanie"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"color": "#673ab7",
|
||||
"name": "projekt"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"color": "#388e3c",
|
||||
"name": "zajęcia"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"color": "#4caf50",
|
||||
"name": "zajęcia dodatkowe"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"color": "#039be5",
|
||||
"name": "informacja"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mobidziennik": {
|
||||
"messagesConfig": {
|
||||
"subjectLength": 100,
|
||||
"htmlMode": "COMPATIBLE"
|
||||
},
|
||||
"uiConfig": {
|
||||
"enableNoticePoints": true
|
||||
}
|
||||
},
|
||||
"librus": {
|
||||
"messagesConfig": {
|
||||
"subjectLength": 150,
|
||||
"bodyLength": 20000,
|
||||
"textStyling": false
|
||||
},
|
||||
"uiConfig": {
|
||||
"enableMarkAsReadAnnouncements": false
|
||||
}
|
||||
},
|
||||
"vulcan": {
|
||||
"messagesConfig": {
|
||||
"subjectLength": 200,
|
||||
"syncRecipientList": false,
|
||||
"needsReadStatus": true
|
||||
}
|
||||
},
|
||||
"idziennik": {
|
||||
"messagesConfig": {
|
||||
"subjectLength": 180,
|
||||
"bodyLength": 1983,
|
||||
"textStyling": false
|
||||
}
|
||||
}
|
||||
}
|
@ -1548,4 +1548,5 @@
|
||||
<string name="login_mode_usos_oauth_guide">TODO</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="app_cannot_load_data">Nie można załadować danych aplikacji</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user