[UI/Home] Implement home card swapping and saving.

This commit is contained in:
Kuba Szczodrzyński 2019-12-02 18:12:52 +01:00
parent 09bc658f97
commit 0a2f252405
13 changed files with 130 additions and 14 deletions

View File

@ -24,6 +24,7 @@
-keep class pl.szczodrzynski.edziennik.utils.models.** { *; } -keep class pl.szczodrzynski.edziennik.utils.models.** { *; }
-keep class pl.szczodrzynski.edziennik.data.db.modules.events.Event { *; } -keep class pl.szczodrzynski.edziennik.data.db.modules.events.Event { *; }
-keep class pl.szczodrzynski.edziennik.data.db.modules.events.EventFull { *; } -keep class pl.szczodrzynski.edziennik.data.db.modules.events.EventFull { *; }
-keep class pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel { *; }
-keepclassmembers class pl.szczodrzynski.edziennik.widgets.WidgetConfig { public *; } -keepclassmembers class pl.szczodrzynski.edziennik.widgets.WidgetConfig { public *; }
-keepnames class pl.szczodrzynski.edziennik.WidgetTimetable -keepnames class pl.szczodrzynski.edziennik.WidgetTimetable
-keepnames class pl.szczodrzynski.edziennik.notifications.WidgetNotifications -keepnames class pl.szczodrzynski.edziennik.notifications.WidgetNotifications

View File

@ -143,6 +143,10 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
public ProfileFull profile; public ProfileFull profile;
public Config config; public Config config;
private static Config mConfig;
public static Config getConfig() {
return mConfig;
}
// other stuff // other stuff
public Gson gson; public Gson gson;
@ -194,6 +198,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
config = new Config(db); config = new Config(db);
config.migrate(this); config.migrate(this);
mConfig = config;
Iconics.init(getApplicationContext()); Iconics.init(getApplicationContext());
Iconics.registerFont(SzkolnyFont.INSTANCE); Iconics.registerFont(SzkolnyFont.INSTANCE);

View File

@ -5,6 +5,7 @@
package pl.szczodrzynski.edziennik.config package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.config.utils.get 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.set
class ConfigSync(private val config: Config) { class ConfigSync(private val config: Config) {
@ -74,14 +75,14 @@ class ConfigSync(private val config: Config) {
private var mTokenMobidziennikList: List<Int>? = null private var mTokenMobidziennikList: List<Int>? = null
var tokenMobidziennikList: List<Int> var tokenMobidziennikList: List<Int>
get() { mTokenMobidziennikList = mTokenMobidziennikList ?: config.values.get("tokenMobidziennikList", listOf()); return mTokenMobidziennikList ?: listOf() } get() { mTokenMobidziennikList = mTokenMobidziennikList ?: config.values.getIntList("tokenMobidziennikList", listOf()); return mTokenMobidziennikList ?: listOf() }
set(value) { config.set("tokenMobidziennikList", value); mTokenMobidziennikList = value } set(value) { config.set("tokenMobidziennikList", value); mTokenMobidziennikList = value }
private var mTokenLibrusList: List<Int>? = null private var mTokenLibrusList: List<Int>? = null
var tokenLibrusList: List<Int> var tokenLibrusList: List<Int>
get() { mTokenLibrusList = mTokenLibrusList ?: config.values.get("tokenLibrusList", listOf()); return mTokenLibrusList ?: listOf() } get() { mTokenLibrusList = mTokenLibrusList ?: config.values.getIntList("tokenLibrusList", listOf()); return mTokenLibrusList ?: listOf() }
set(value) { config.set("tokenLibrusList", value); mTokenLibrusList = value } set(value) { config.set("tokenLibrusList", value); mTokenLibrusList = value }
private var mTokenVulcanList: List<Int>? = null private var mTokenVulcanList: List<Int>? = null
var tokenVulcanList: List<Int> var tokenVulcanList: List<Int>
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.get("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() } get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value } set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
} }

View File

@ -7,6 +7,7 @@ package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.config.utils.get import pl.szczodrzynski.edziennik.config.utils.get
import pl.szczodrzynski.edziennik.config.utils.getIntList import pl.szczodrzynski.edziennik.config.utils.getIntList
import pl.szczodrzynski.edziennik.config.utils.set import pl.szczodrzynski.edziennik.config.utils.set
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
class ConfigUI(private val config: Config) { class ConfigUI(private val config: Config) {
private var mTheme: Int? = null private var mTheme: Int? = null
@ -43,4 +44,9 @@ class ConfigUI(private val config: Config) {
var agendaViewType: Int var agendaViewType: Int
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: 0 } get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: 0 }
set(value) { config.set("agendaViewType", value); mAgendaViewType = value } set(value) { config.set("agendaViewType", value); mAgendaViewType = 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 }
} }

View File

@ -74,8 +74,9 @@ fun HashMap<String, String?>.get(key: String, default: JsonObject?): JsonObject?
fun HashMap<String, String?>.get(key: String, default: JsonArray?): JsonArray? { fun HashMap<String, String?>.get(key: String, default: JsonArray?): JsonArray? {
return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default
} }
fun <T> HashMap<String, String?>.get(key: String, default: List<T>?): List<T>? { /* !!! cannot use mutable list here - modifying it will not update the DB */
return this[key]?.let { gson.fromJson<List<T>>(it, object: TypeToken<List<T>>(){}.type) } ?: default 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>? { 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 return this[key]?.let { gson.fromJson<List<String>>(it, object: TypeToken<List<String>>(){}.type) } ?: default

View File

@ -0,0 +1,44 @@
/*
* 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.getInt
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardModel
import pl.szczodrzynski.edziennik.utils.models.Time
class ConfigGsonUtils {
fun <T> deserializeList(gson: Gson, str: String?, classOfT: Class<T>): List<T> {
val json = JsonParser().parse(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
}
}

View File

@ -5,6 +5,29 @@
package pl.szczodrzynski.edziennik.ui.modules.home package pl.szczodrzynski.edziennik.ui.modules.home
interface HomeCard { interface HomeCard {
companion object {
/**
* A card is visible on every profile.
* On a unified home fragment, shows
* summary data from every profile.
* Not every card may work like this.
*/
const val PROFILE_UNIFIED = -1
/**
* A card is visible on every profile, but does
* not show every profile, just the currently
* loaded one.
*/
const val PROFILE_ALL = 0
const val CARD_LUCKY_NUMBER = 1
const val CARD_TIMETABLE = 2
const val CARD_GRADES = 3
const val CARD_EVENTS = 4
}
val id: Int
fun bind(position: Int, holder: HomeCardAdapter.ViewHolder) fun bind(position: Int, holder: HomeCardAdapter.ViewHolder)
fun unbind(position: Int, holder: HomeCardAdapter.ViewHolder) fun unbind(position: Int, holder: HomeCardAdapter.ViewHolder)
} }

View File

@ -0,0 +1,12 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-2.
*/
package pl.szczodrzynski.edziennik.ui.modules.home
import java.io.Serializable
data class HomeCardModel(
val profileId: Int,
val cardId: Int
) : Serializable

View File

@ -15,7 +15,7 @@ import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.startCoroutineTimer import pl.szczodrzynski.edziennik.startCoroutineTimer
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class HomeDummyCard(val id: Int) : HomeCard, CoroutineScope { class HomeDummyCard(override val id: Int) : HomeCard, CoroutineScope {
companion object { companion object {
private const val TAG = "HomeDummyCard" private const val TAG = "HomeDummyCard"
} }

View File

@ -41,6 +41,12 @@ class HomeFragmentV2 : Fragment(), CoroutineScope {
private const val TAG = "HomeFragment" private const val TAG = "HomeFragment"
fun swapCards(fromPosition: Int, toPosition: Int, cardAdapter: HomeCardAdapter) { fun swapCards(fromPosition: Int, toPosition: Int, cardAdapter: HomeCardAdapter) {
val homeCards = App.getConfig().ui.homeCards.toMutableList()
val fromPair = homeCards[fromPosition]
homeCards[fromPosition] = homeCards[toPosition]
homeCards[toPosition] = fromPair
App.getConfig().ui.homeCards = homeCards
val fromCard = cardAdapter.items[fromPosition] val fromCard = cardAdapter.items[fromPosition]
cardAdapter.items[fromPosition] = cardAdapter.items[toPosition] cardAdapter.items[fromPosition] = cardAdapter.items[toPosition]
cardAdapter.items[toPosition] = fromCard cardAdapter.items[toPosition] = fromCard
@ -93,11 +99,28 @@ class HomeFragmentV2 : Fragment(), CoroutineScope {
}) })
) )
val items = mutableListOf<HomeCard>( val showUnified = false
HomeLuckyNumberCard(0, app, activity, this, app.profile),
HomeTimetableCard(1, app, activity, this, app.profile), val cards = app.config.ui.homeCards.filter { it.profileId == app.profile.id }.toMutableList()
HomeGradesCard(2, app, activity, this, app.profile) if (cards.isEmpty()) {
) cards += listOf(
HomeCardModel(app.profile.id, HomeCard.CARD_LUCKY_NUMBER),
HomeCardModel(app.profile.id, HomeCard.CARD_TIMETABLE),
/*HomeCardModel(app.profile.id, HomeCard.CARD_EVENTS),*/
HomeCardModel(app.profile.id, HomeCard.CARD_GRADES)
)
app.config.ui.homeCards = app.config.ui.homeCards.toMutableList().also { it.addAll(cards) }
}
val items = mutableListOf<HomeCard>()
cards.mapNotNullTo(items) {
when (it.cardId) {
HomeCard.CARD_LUCKY_NUMBER -> HomeLuckyNumberCard(it.cardId, app, activity, this, app.profile)
HomeCard.CARD_TIMETABLE -> HomeTimetableCard(it.cardId, app, activity, this, app.profile)
HomeCard.CARD_GRADES -> HomeGradesCard(it.cardId, app, activity, this, app.profile)
else -> null
}
}
val adapter = HomeCardAdapter(items) val adapter = HomeCardAdapter(items)
val itemTouchHelper = ItemTouchHelper(CardItemTouchHelperCallback(adapter, b.refreshLayout)) val itemTouchHelper = ItemTouchHelper(CardItemTouchHelperCallback(adapter, b.refreshLayout))

View File

@ -43,7 +43,7 @@ import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class HomeGradesCard( class HomeGradesCard(
val id: Int, override val id: Int,
val app: App, val app: App,
val activity: MainActivity, val activity: MainActivity,
val fragment: HomeFragmentV2, val fragment: HomeFragmentV2,

View File

@ -26,7 +26,7 @@ import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class HomeLuckyNumberCard( class HomeLuckyNumberCard(
val id: Int, override val id: Int,
val app: App, val app: App,
val activity: MainActivity, val activity: MainActivity,
val fragment: HomeFragmentV2, val fragment: HomeFragmentV2,

View File

@ -32,7 +32,7 @@ import pl.szczodrzynski.navlib.colorAttr
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class HomeTimetableCard( class HomeTimetableCard(
val id: Int, override val id: Int,
val app: App, val app: App,
val activity: MainActivity, val activity: MainActivity,
val fragment: HomeFragmentV2, val fragment: HomeFragmentV2,