[Config] Implement per-profile config. Update timetable card.

This commit is contained in:
Kuba Szczodrzyński 2019-11-28 21:45:27 +01:00
parent a36fb09bc3
commit 928b73f139
16 changed files with 214 additions and 61 deletions

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik
import android.util.Log
import androidx.work.Configuration
class Szkolny : /*MultiDexApplication(),*/ Configuration.Provider {
/*val db by lazy { AppDb.getDatabase(this) }
val networkUtils by lazy { NetworkUtils(this) }
val notifier by lazy { Notifier(this) }
val permissionChecker by lazy { PermissionChecker(this) }
val cookieJar by lazy { PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(this)) }
val deviceId: String by lazy { Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) ?: "" }*/
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setMinimumLoggingLevel(Log.VERBOSE)
.build()
/*override fun onCreate() {
super.onCreate()
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
CaocConfig.Builder.create()
.backgroundMode(CaocConfig.BACKGROUND_MODE_SHOW_CUSTOM)
.enabled(true)
.showErrorDetails(true)
.showRestartButton(true)
.logErrorOnRestart(true)
.trackActivities(true)
.minTimeBetweenCrashesMs(60*1000)
.errorDrawable(R.drawable.ic_rip)
.restartActivity(MainActivity::class.java)
.errorActivity(CrashActivity::class.java)
//.eventListener(new YourCustomEventListener())
.apply()
Iconics.init(applicationContext)
Iconics.registerFont(SzkolnyFont)
}*/
}

View File

@ -52,9 +52,9 @@ class WidgetTimetable : AppWidgetProvider() {
val app = context.applicationContext as App
var bellSyncDiffMillis: Long = 0
if (app.appConfig.bellSyncDiff != null) {
bellSyncDiffMillis = (app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000).toLong()
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier.toLong()
app.config.timetable.bellSyncDiff?.let {
bellSyncDiffMillis = (it.hour * 60 * 60 * 1000 + it.minute * 60 * 1000 + it.second * 1000).toLong()
bellSyncDiffMillis *= app.config.timetable.bellSyncMultiplier.toLong()
bellSyncDiffMillis *= -1
}

View File

@ -0,0 +1,9 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
interface AbstractConfig {
fun set(key: String, value: String?)
}

View File

@ -8,10 +8,15 @@ 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.ConfigMigration
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 Config(val db: AppDb) : CoroutineScope {
class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
companion object {
const val DATA_VERSION = 1
}
@ -20,9 +25,7 @@ class Config(val db: AppDb) : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Default
private var profileId: Int? = null
val values: HashMap<String, String?> = hashMapOf()
//private val profileValues: HashMap<String, String?> = hashMapOf()
val ui by lazy { ConfigUI(this) }
val sync by lazy { ConfigSync(this) }
@ -32,26 +35,26 @@ class Config(val db: AppDb) : CoroutineScope {
private var mDataVersion: Int? = null
var dataVersion: Int
get() { mDataVersion = mDataVersion ?: values.get("dataVersion", 0); return mDataVersion ?: 0 }
set(value) { set(-1, "dataVersion", value); mDataVersion = value }
set(value) { set("dataVersion", value); mDataVersion = value }
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
init {
db.configDao().getAllNow().toHashMap(values)
rawEntries.toHashMap(-1, values)
if (dataVersion < DATA_VERSION)
ConfigMigration(this)
}
fun setProfile(profileId: Int) {
this.profileId = profileId
//profileValues.clear()
//db.configDao().getAllNow(profileId).toHashMap(profileValues)
fun getFor(profileId: Int): ProfileConfig {
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, rawEntries)
}
fun set(profileId: Int, key: String, value: String?) {
//if (profileId == -1)
fun setProfile(profileId: Int) {
}
override fun set(key: String, value: String?) {
values[key] = value
/*else
profileValues[key] = value*/
launch {
db.configDao().add(ConfigEntry(profileId, key, value))
db.configDao().add(ConfigEntry(-1, key, value))
}
}
}

View File

@ -4,24 +4,27 @@
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.config.utils.get
import pl.szczodrzynski.edziennik.config.utils.set
class ConfigSync(val config: Config) {
private var mSyncEnabled: Boolean? = null
var enabled: Boolean
get() { mSyncEnabled = mSyncEnabled ?: config.values.get("syncEnabled", true); return mSyncEnabled ?: true }
set(value) { config.set(-1, "syncEnabled", value); mSyncEnabled = value }
set(value) { config.set("syncEnabled", value); mSyncEnabled = value }
private var mSyncOnlyWifi: Boolean? = null
var onlyWifi: Boolean
get() { mSyncOnlyWifi = mSyncOnlyWifi ?: config.values.get("syncOnlyWifi", false); return mSyncOnlyWifi ?: notifyAboutUpdates }
set(value) { config.set(-1, "syncOnlyWifi", value); mSyncOnlyWifi = value }
set(value) { config.set("syncOnlyWifi", value); mSyncOnlyWifi = value }
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(-1, "syncInterval", value); mSyncInterval = value }
set(value) { config.set("syncInterval", value); mSyncInterval = value }
private var mNotifyAboutUpdates: Boolean? = null
var notifyAboutUpdates: Boolean
get() { mNotifyAboutUpdates = mNotifyAboutUpdates ?: config.values.get("notifyAboutUpdates", true); return mNotifyAboutUpdates ?: true }
set(value) { config.set(-1, "notifyAboutUpdates", value); mNotifyAboutUpdates = value }
set(value) { config.set("notifyAboutUpdates", value); mNotifyAboutUpdates = value }
}

View File

@ -4,16 +4,18 @@
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(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(-1, "bellSyncMultiplier", value); mBellSyncMultiplier = value }
set(value) { config.set("bellSyncMultiplier", value); mBellSyncMultiplier = value }
private var mBellSyncDiff: Time? = null
var bellSyncDiff: Time?
get() { mBellSyncDiff = mBellSyncDiff ?: config.values.get("bellSyncDiff", null as Time?); return mBellSyncDiff }
set(value) { config.set(-1, "bellSyncDiff", value); mBellSyncDiff = value }
set(value) { config.set("bellSyncDiff", value); mBellSyncDiff = value }
}

View File

@ -4,29 +4,33 @@
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
class ConfigUI(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(-1, "theme", value); mTheme = value }
set(value) { config.set("theme", value); mTheme = value }
private var mHeaderBackground: String? = null
var headerBackground: String?
get() { mHeaderBackground = mHeaderBackground ?: config.values.get("headerBackground", null as String?); return mHeaderBackground }
set(value) { config.set(-1, "headerBg", value); mHeaderBackground = value }
set(value) { config.set("headerBg", value); mHeaderBackground = value }
private var mAppBackground: String? = null
var appBackground: String?
get() { mAppBackground = mAppBackground ?: config.values.get("appBackground", null as String?); return mAppBackground }
set(value) { config.set(-1, "appBg", value); mAppBackground = value }
set(value) { config.set("appBg", value); mAppBackground = value }
private var mMiniMenuVisible: Boolean? = null
var miniMenuVisible: Boolean
get() { mMiniMenuVisible = mMiniMenuVisible ?: config.values.get("miniMenuVisible", false); return mMiniMenuVisible ?: false }
set(value) { config.set(-1, "miniMenuVisible", value); mMiniMenuVisible = value }
set(value) { config.set("miniMenuVisible", value); mMiniMenuVisible = value }
private var mMiniMenuButtons: List<Int>? = null
var miniMenuButtons: List<Int>
get() { mMiniMenuButtons = mMiniMenuButtons ?: config.values.getIntList("miniMenuButtons", listOf()); return mMiniMenuButtons ?: listOf() }
set(value) { config.set(-1, "miniMenuButtons", value); mMiniMenuButtons = value }
set(value) { config.set("miniMenuButtons", value); mMiniMenuButtons = value }
}

View File

@ -0,0 +1,51 @@
/*
* 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.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 {
companion object {
const val DATA_VERSION = 1
}
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Default
val values: HashMap<String, String?> = hashMapOf()
/*
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 }
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))
}
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
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.modules.profiles.Profile.Companion.COLOR_MODE_WEIGHTED
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile.Companion.YEAR_ALL_GRADES
class ProfileConfigGrades(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 }
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 mCountZeroToAvg: Boolean? = null
var countZeroToAvg: Boolean
get() { mCountZeroToAvg = mCountZeroToAvg ?: config.values.get("countZeroToAvg", true); return mCountZeroToAvg ?: true }
set(value) { config.set("countZeroToAvg", value); mCountZeroToAvg = value }
}

View File

@ -1,8 +1,8 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
package pl.szczodrzynski.edziennik.config.db
import androidx.room.Dao
import androidx.room.Insert

View File

@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
*/
package pl.szczodrzynski.edziennik.config
package pl.szczodrzynski.edziennik.config.db
import androidx.room.Entity

View File

@ -1,48 +1,50 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
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 Config.set(profileId: Int, key: String, value: Int) {
set(profileId, key, value.toString())
fun AbstractConfig.set(key: String, value: Int) {
set(key, value.toString())
}
fun Config.set(profileId: Int, key: String, value: Boolean) {
set(profileId, key, value.toString())
fun AbstractConfig.set(key: String, value: Boolean) {
set(key, value.toString())
}
fun Config.set(profileId: Int, key: String, value: Long) {
set(profileId, key, value.toString())
fun AbstractConfig.set(key: String, value: Long) {
set(key, value.toString())
}
fun Config.set(profileId: Int, key: String, value: Float) {
set(profileId, key, value.toString())
fun AbstractConfig.set(key: String, value: Float) {
set(key, value.toString())
}
fun Config.set(profileId: Int, key: String, value: Date?) {
set(profileId, key, value?.stringY_m_d)
fun AbstractConfig.set(key: String, value: Date?) {
set(key, value?.stringY_m_d)
}
fun Config.set(profileId: Int, key: String, value: Time?) {
set(profileId, key, value?.stringValue)
fun AbstractConfig.set(key: String, value: Time?) {
set(key, value?.stringValue)
}
fun Config.set(profileId: Int, key: String, value: JsonElement?) {
set(profileId, key, value?.toString())
fun AbstractConfig.set(key: String, value: JsonElement?) {
set(key, value?.toString())
}
fun Config.set(profileId: Int, key: String, value: List<Any>?) {
set(profileId, key, value?.let { gson.toJson(it) })
fun AbstractConfig.set(key: String, value: List<Any>?) {
set(key, value?.let { gson.toJson(it) })
}
fun Config.setStringList(profileId: Int, key: String, value: List<String>?) {
set(profileId, key, value?.let { gson.toJson(it) })
fun AbstractConfig.setStringList(key: String, value: List<String>?) {
set(key, value?.let { gson.toJson(it) })
}
fun Config.setIntList(profileId: Int, key: String, value: List<Int>?) {
set(profileId, key, value?.let { gson.toJson(it) })
fun AbstractConfig.setIntList(key: String, value: List<Int>?) {
set(key, value?.let { gson.toJson(it) })
}
fun Config.setLongList(profileId: Int, key: String, value: List<Long>?) {
set(profileId, key, value?.let { gson.toJson(it) })
fun AbstractConfig.setLongList(key: String, value: List<Long>?) {
set(key, value?.let { gson.toJson(it) })
}
fun HashMap<String, String?>.get(key: String, default: String?): String? {
@ -85,9 +87,10 @@ fun HashMap<String, String?>.getLongList(key: String, default: List<Long>?): Lis
return this[key]?.let { gson.fromJson<List<Long>>(it, object: TypeToken<List<Long>>(){}.type) } ?: default
}
fun List<ConfigEntry>.toHashMap(map: HashMap<String, String?>) {
fun List<ConfigEntry>.toHashMap(profileId: Int, map: HashMap<String, String?>) {
map.clear()
forEach {
map[it.key] = it.value
if (it.profileId == profileId)
map[it.key] = it.value
}
}

View File

@ -1,10 +1,11 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-26.
* Copyright (c) Kuba Szczodrzyński 2019-11-27.
*/
package pl.szczodrzynski.edziennik.config
package pl.szczodrzynski.edziennik.config.utils
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.config.Config
class ConfigMigration(config: Config) {
init { config.apply {

View File

@ -10,8 +10,8 @@ import androidx.room.TypeConverters;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import pl.szczodrzynski.edziennik.config.ConfigDao;
import pl.szczodrzynski.edziennik.config.ConfigEntry;
import pl.szczodrzynski.edziennik.config.db.ConfigDao;
import pl.szczodrzynski.edziennik.config.db.ConfigEntry;
import pl.szczodrzynski.edziennik.data.db.converters.ConverterDate;
import pl.szczodrzynski.edziennik.data.db.converters.ConverterDateInt;
import pl.szczodrzynski.edziennik.data.db.converters.ConverterJsonObject;

View File

@ -145,6 +145,11 @@ class HomeTimetableCard(
if (isToday) {
// today
b.dayInfo.setText(R.string.home_timetable_today)
b.lessonInfo.setText(
R.string.home_timetable_lessons_remaining,
lessons.size,
lastLesson?.displayEndTime?.stringHM ?: "?"
)
counterStart = firstLesson?.displayStartTime
counterEnd = firstLesson?.displayEndTime
val isOngoing = counterStart <= now && now <= counterEnd

View File

@ -1054,4 +1054,5 @@
<string name="home_timetable_today">Dzisiaj</string>
<string name="home_timetable_lesson_ongoing">Teraz: %s</string>
<string name="home_timetable_lesson_not_started">Za chwilę: %s</string>
<string name="home_timetable_lessons_remaining">Pozostało lekcji: %d - do %s</string>
</resources>