[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.data.db.modules.events.Event { *; }
-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 *; }
-keepnames class pl.szczodrzynski.edziennik.WidgetTimetable
-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 Config config;
private static Config mConfig;
public static Config getConfig() {
return mConfig;
}
// other stuff
public Gson gson;
@ -194,6 +198,7 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
config = new Config(db);
config.migrate(this);
mConfig = config;
Iconics.init(getApplicationContext());
Iconics.registerFont(SzkolnyFont.INSTANCE);

View File

@ -5,6 +5,7 @@
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 ConfigSync(private val config: Config) {
@ -74,14 +75,14 @@ class ConfigSync(private val config: Config) {
private var mTokenMobidziennikList: List<Int>? = null
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 }
private var mTokenLibrusList: List<Int>? = null
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 }
private var mTokenVulcanList: List<Int>? = null
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 }
}

View File

@ -7,6 +7,7 @@ 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.ui.modules.home.HomeCardModel
class ConfigUI(private val config: Config) {
private var mTheme: Int? = null
@ -43,4 +44,9 @@ class ConfigUI(private val config: Config) {
var agendaViewType: Int
get() { mAgendaViewType = mAgendaViewType ?: config.values.get("agendaViewType", 0); return mAgendaViewType ?: 0 }
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? {
return this[key]?.let { JsonParser().parse(it)?.asJsonArray } ?: default
}
fun <T> HashMap<String, String?>.get(key: String, default: List<T>?): List<T>? {
return this[key]?.let { gson.fromJson<List<T>>(it, object: TypeToken<List<T>>(){}.type) } ?: 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

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
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 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 kotlin.coroutines.CoroutineContext
class HomeDummyCard(val id: Int) : HomeCard, CoroutineScope {
class HomeDummyCard(override val id: Int) : HomeCard, CoroutineScope {
companion object {
private const val TAG = "HomeDummyCard"
}

View File

@ -41,6 +41,12 @@ class HomeFragmentV2 : Fragment(), CoroutineScope {
private const val TAG = "HomeFragment"
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]
cardAdapter.items[fromPosition] = cardAdapter.items[toPosition]
cardAdapter.items[toPosition] = fromCard
@ -93,11 +99,28 @@ class HomeFragmentV2 : Fragment(), CoroutineScope {
})
)
val items = mutableListOf<HomeCard>(
HomeLuckyNumberCard(0, app, activity, this, app.profile),
HomeTimetableCard(1, app, activity, this, app.profile),
HomeGradesCard(2, app, activity, this, app.profile)
)
val showUnified = false
val cards = app.config.ui.homeCards.filter { it.profileId == app.profile.id }.toMutableList()
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 itemTouchHelper = ItemTouchHelper(CardItemTouchHelperCallback(adapter, b.refreshLayout))

View File

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

View File

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

View File

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