Skip to content

Commit d675fd4

Browse files
committed
Improved parsing of preferences
1 parent 24da3c9 commit d675fd4

File tree

7 files changed

+93
-95
lines changed

7 files changed

+93
-95
lines changed

app/src/main/java/nl/giejay/android/tv/immich/album/AlbumDetailsFragment.kt

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,26 @@ import nl.giejay.android.tv.immich.home.HomeFragmentDirections
1313
import nl.giejay.android.tv.immich.shared.prefs.LivePreference
1414
import nl.giejay.android.tv.immich.shared.prefs.LiveSharedPreferences
1515
import nl.giejay.android.tv.immich.shared.prefs.PHOTOS_SORTING
16+
import nl.giejay.android.tv.immich.shared.prefs.PHOTOS_SORTING_FOR_SPECIFIC_ALBUM
17+
import nl.giejay.android.tv.immich.shared.prefs.PhotosOrder
18+
import nl.giejay.android.tv.immich.shared.prefs.Pref
1619
import nl.giejay.android.tv.immich.shared.prefs.PreferenceManager
1720

1821

22+
1923
class AlbumDetailsFragment : GenericAssetFragment() {
2024
private lateinit var albumId: String
2125
private lateinit var albumName: String
22-
private lateinit var livePref: LivePreference<String>
26+
private var currentSort: PhotosOrder? = null
27+
private lateinit var prefKey: PHOTOS_SORTING_FOR_SPECIFIC_ALBUM
2328
private var pageToBucket: Map<Int, String>? = null
24-
private var currentSort: String? = null
2529

2630
override fun onCreate(savedInstanceState: Bundle?) {
2731
albumId = AlbumDetailsFragmentArgs.fromBundle(requireArguments()).albumId
2832
albumName = AlbumDetailsFragmentArgs.fromBundle(requireArguments()).albumName
29-
super.onCreate(savedInstanceState)
30-
livePref = LiveSharedPreferences(PreferenceManager.sharedPreference)
31-
.getString(PreferenceManager.keyAlbumsSorting(albumId), PHOTOS_SORTING.defaultValue.toString(), true)
32-
currentSort = livePref.value
33-
}
34-
35-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
36-
super.onViewCreated(view, savedInstanceState)
37-
livePref.observe(viewLifecycleOwner) { state ->
33+
prefKey = PHOTOS_SORTING_FOR_SPECIFIC_ALBUM(albumId)
34+
currentSort = PhotosOrder.valueOf(PreferenceManager.getString(prefKey.key(), prefKey.defaultValue.toString()))
35+
PreferenceManager.subscribe(prefKey) { state ->
3836
if(state != currentSort){
3937
// need to refetch everything because of the timeline buckets approach
4038
clearState()
@@ -43,16 +41,17 @@ class AlbumDetailsFragment : GenericAssetFragment() {
4341
fetchInitialItems()
4442
}
4543
}
44+
super.onCreate(savedInstanceState)
4645
}
4746

4847
override fun sortItems(items: List<Asset>): List<Asset> {
49-
return items.sortedWith(PreferenceManager.getSortingForAlbum(albumId).sort)
48+
return items.sortedWith(currentSort!!.sort)
5049
}
5150

5251
override suspend fun loadData(): Either<String, List<Asset>> {
5352
if (pageToBucket == null) {
5453
// initial call, fetch the buckets
55-
val listBuckets = apiClient.listBuckets(albumId, PreferenceManager.getSortingForAlbum(albumId))
54+
val listBuckets = apiClient.listBuckets(albumId, currentSort!!)
5655
return listBuckets.map { list ->
5756
pageToBucket = list.associateBy({ list.indexOf(it) + 1 }, { it.timeBucket })
5857
return internalLoadData(emptyList())
@@ -78,7 +77,7 @@ class AlbumDetailsFragment : GenericAssetFragment() {
7877
override suspend fun loadItems(apiClient: ApiClient, page: Int, pageCount: Int): Either<String, List<Asset>> {
7978
val bucketForPage = pageToBucket!![page]
8079
return if (bucketForPage != null) {
81-
apiClient.getAssetsForBucket(albumId, bucketForPage, PreferenceManager.getSortingForAlbum(albumId))
80+
apiClient.getAssetsForBucket(albumId, bucketForPage, currentSort!!)
8281
} else {
8382
Either.Right(emptyList())
8483
}

app/src/main/java/nl/giejay/android/tv/immich/album/AlbumFragment.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,9 @@ class AlbumFragment : VerticalCardGridFragment<Album>() {
2020

2121
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
2222
super.onViewCreated(view, savedInstanceState)
23-
LiveSharedPreferences(PreferenceManager.sharedPreference)
24-
.getString(PreferenceManager.get(ALBUMS_SORTING).toString(), ALBUMS_SORTING.defaultValue.toString(), true)
25-
.observe(viewLifecycleOwner) { _ ->
26-
resortItems()
27-
}
23+
PreferenceManager.subscribe(ALBUMS_SORTING) {
24+
resortItems()
25+
}
2826
}
2927

3028
override fun sortItems(items: List<Album>): List<Album> {
@@ -36,7 +34,7 @@ class AlbumFragment : VerticalCardGridFragment<Album>() {
3634
} else {
3735
try {
3836
items.sortedWith(PreferenceManager.get(ALBUMS_SORTING).sort)
39-
} catch (e: IllegalArgumentException){
37+
} catch (e: IllegalArgumentException) {
4038
Timber.e(e, "Could not sort using sorting order: " + PreferenceManager.get(ALBUMS_SORTING).toString())
4139
items
4240
}

app/src/main/java/nl/giejay/android/tv/immich/settings/AlbumDetailsSettingsFragment.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import androidx.preference.PreferenceScreen
88
import arrow.core.Either
99
import arrow.core.left
1010
import nl.giejay.android.tv.immich.R
11+
import nl.giejay.android.tv.immich.shared.prefs.PHOTOS_SORTING_FOR_SPECIFIC_ALBUM
12+
import nl.giejay.android.tv.immich.shared.prefs.PhotosOrder
1113
import nl.giejay.android.tv.immich.shared.prefs.PrefScreen
1214
import nl.giejay.android.tv.immich.shared.prefs.PreferenceManager
1315

@@ -23,12 +25,13 @@ class AlbumDetailsInnerSettingsFragment : SettingsScreenFragment.SettingsInnerFr
2325
val albumId = bundle.getString("albumId")!!
2426
val albumName = bundle.getString("albumName")
2527
setTitle("$albumName settings")
26-
val sortPref = findPreference<ListPreference>("photos_sorting_specific_album")
27-
val sortingForAlbum = PreferenceManager.getSortingForAlbum(albumId)
28-
sortPref!!.value = sortingForAlbum.toString()
28+
val sortPref = findPreference<ListPreference>("photos_sorting_specific_album")!!
29+
val photosSortingForSpecificAlbum = PHOTOS_SORTING_FOR_SPECIFIC_ALBUM(albumId)
30+
val sortingForAlbum = PreferenceManager.getString(photosSortingForSpecificAlbum.key(), photosSortingForSpecificAlbum.defaultValue.toString())
31+
sortPref.value = sortingForAlbum
2932
sortPref.title = "Sort photos in $albumName by"
3033
sortPref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener{_, newValue ->
31-
PreferenceManager.saveSortingForAlbum(albumId, newValue as String)
34+
PreferenceManager.save(photosSortingForSpecificAlbum, PhotosOrder.valueOf(newValue as String))
3235
true
3336
}
3437
}

app/src/main/java/nl/giejay/android/tv/immich/shared/prefs/LiveSharedPreferences.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ class LiveSharedPreferences(private val preferences: SharedPreferences) {
2323
return LivePreference(updates, preferences, key, defaultValue, ignoreInitialValue)
2424
}
2525

26-
fun <T>subscribe(key: String, defaultValue: T, onChange: (T) -> Unit){
27-
return LivePreference(updates, preferences, key, defaultValue).observeForever{value ->
28-
onChange(value)
26+
fun <T, PREFTYPE>subscribeTyped(key: Pref<T, *, PREFTYPE>, onChange: (T) -> Unit){
27+
return LivePreference(updates, preferences, key.key(), key.toPrefValue(key.defaultValue)).observeForever{storedPrefType ->
28+
onChange(key.fromPrefValue(storedPrefType))
2929
}
3030
}
3131

app/src/main/java/nl/giejay/android/tv/immich/shared/prefs/Pref.kt

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,46 @@ import nl.giejay.android.tv.immich.shared.prefs.PreferenceManager.sharedPreferen
1313

1414

1515
sealed class PrefScreen(val title: String, val key: String, val children: List<PrefCategory>, val onViewCreated: (PreferenceManager) -> Unit = {}){
16-
fun findByKey(key: String): Pref<*, *>? {
16+
fun findByKey(key: String): Pref<*, *, *>? {
1717
return children.firstNotNullOfOrNull { it.findByKey(key) }
1818
}
1919
}
2020

21-
data class PrefCategory(val title: String, val children: List<Pref<*, *>>){
22-
fun findByKey(key: String): Pref<*, *>? {
21+
data class PrefCategory(val title: String, val children: List<Pref<*, *, *>>){
22+
fun findByKey(key: String): Pref<*, *, *>? {
2323
return children.find { it.key() == key }
2424
}
2525
}
2626

27-
sealed class Pref<T, PREF : Preference>(val defaultValue: T, val title: String, val summary: String) {
27+
sealed class Pref<T, PREF : Preference, PREFTYPE>(val defaultValue: T, val title: String, val summary: String) {
2828
open fun key() = javaClass.simpleName.lowercase()
2929
abstract fun save(sharedPreferences: SharedPreferences, value: T)
30-
open fun parse(any: Any?): T {
31-
return any as T
30+
open fun fromPrefValue(prefValue: PREFTYPE): T {
31+
// by default stored pref value and the type of the Pref is the same, but it can differ with for example ListPreferences<Int>
32+
// stored by String values
33+
return prefValue as T
3234
}
3335

3436
open fun onClick(context: Context, controller: NavController): Boolean {
3537
// can be implemented by children
3638
return false
3739
}
3840

39-
open fun parseDefaultValue(value: T): Any = value as Any
41+
open fun toPrefValue(value: T): PREFTYPE = value as PREFTYPE
4042

4143
fun createPreference(context: Context): PREF {
4244
val createPref = createPref(context)
4345
createPref.key = key()
4446
createPref.title = title
45-
createPref.setDefaultValue(parseDefaultValue(defaultValue))
47+
createPref.setDefaultValue(toPrefValue(defaultValue))
4648
createPref.summary = summary
4749
return createPref
4850
}
4951

5052
abstract fun createPref(context: Context): PREF
5153
}
5254

53-
sealed class NotUserEditableStringPref(title: String, summary: String): Pref<String, Preference>("", title, summary){
55+
sealed class NotUserEditableStringPref(title: String, summary: String): Pref<String, Preference, String>("", title, summary){
5456
override fun save(sharedPreferences: SharedPreferences, value: String) {
5557
sharedPreference.edit().putString(key(), value).apply()
5658
}
@@ -60,7 +62,7 @@ sealed class NotUserEditableStringPref(title: String, summary: String): Pref<Str
6062
}
6163
}
6264

63-
sealed class ActionPref(title: String, summary: String, val onClick: (Context, NavController) -> Boolean): Pref<String, Preference>("", title, summary){
65+
sealed class ActionPref(title: String, summary: String, val onClick: (Context, NavController) -> Boolean): Pref<String, Preference, String>("", title, summary){
6466
override fun save(sharedPreferences: SharedPreferences, value: String) {
6567

6668
}
@@ -77,16 +79,16 @@ sealed class ActionPref(title: String, summary: String, val onClick: (Context, N
7779
}
7880

7981
sealed class EnumPref<T : Enum<T>>(defaultValue: T, title: String, summary: String,
80-
val titlesResourceId: Int, val valuesResourceId: Int) : Pref<T, ListPreference>(defaultValue, title, summary) {
82+
val titlesResourceId: Int, val valuesResourceId: Int) : Pref<T, ListPreference, String>(defaultValue, title, summary) {
8183
override fun save(sharedPreferences: SharedPreferences, value: T) {
8284
sharedPreferences.edit().putString(key(), value.toString()).apply()
8385
}
8486

85-
override fun parseDefaultValue(value: T): Any {
87+
override fun toPrefValue(value: T): String {
8688
return value.toString()
8789
}
8890

89-
abstract override fun parse(any: Any?): T
91+
abstract override fun fromPrefValue(prefValue: String): T
9092

9193
override fun createPref(context: Context): ListPreference {
9294
val listPreference = ListPreference(context)
@@ -97,7 +99,7 @@ sealed class EnumPref<T : Enum<T>>(defaultValue: T, title: String, summary: Stri
9799
}
98100
}
99101

100-
sealed class BooleanPref(defaultValue: Boolean, title: String, summary: String) : Pref<Boolean, CheckBoxPreference>(defaultValue, title, summary) {
102+
sealed class BooleanPref(defaultValue: Boolean, title: String, summary: String) : Pref<Boolean, CheckBoxPreference, Boolean>(defaultValue, title, summary) {
101103
override fun save(sharedPreferences: SharedPreferences, value: Boolean) {
102104
sharedPreference.edit().putBoolean(key(), value).apply()
103105
}
@@ -107,7 +109,7 @@ sealed class BooleanPref(defaultValue: Boolean, title: String, summary: String)
107109
}
108110
}
109111

110-
sealed class StringPref(defaultValue: String, title: String, summary: String) : Pref<String, EditTextPreference>(defaultValue, title, summary) {
112+
sealed class StringPref(defaultValue: String, title: String, summary: String) : Pref<String, EditTextPreference, String>(defaultValue, title, summary) {
111113
override fun save(sharedPreferences: SharedPreferences, value: String) {
112114
sharedPreference.edit().putString(key(), value).apply()
113115
}
@@ -117,7 +119,7 @@ sealed class StringPref(defaultValue: String, title: String, summary: String) :
117119
}
118120
}
119121

120-
sealed class StringSetPref(defaultValue: Set<String>, title: String, summary: String) : Pref<Set<String>, ListPreference>(defaultValue,
122+
sealed class StringSetPref(defaultValue: Set<String>, title: String, summary: String) : Pref<Set<String>, ListPreference, Set<String>>(defaultValue,
121123
title,
122124
summary) {
123125
override fun save(sharedPreferences: SharedPreferences, value: Set<String>) {
@@ -129,7 +131,7 @@ sealed class StringSetPref(defaultValue: Set<String>, title: String, summary: St
129131
}
130132
}
131133

132-
sealed class IntSeekbarPref(defaultValue: Int, title: String, summary: String) : Pref<Int, SeekBarPreference>(defaultValue, title, summary) {
134+
sealed class IntSeekbarPref(defaultValue: Int, title: String, summary: String) : Pref<Int, SeekBarPreference, Int>(defaultValue, title, summary) {
133135
override fun save(sharedPreferences: SharedPreferences, value: Int) {
134136
sharedPreference.edit().putInt(key(), value).apply()
135137
}
@@ -140,15 +142,19 @@ sealed class IntSeekbarPref(defaultValue: Int, title: String, summary: String) :
140142
}
141143

142144
sealed class IntListPref(defaultValue: Int, title: String, summary: String,
143-
val titlesResourceId: Int, val valuesResourceId: Int) : Pref<Int, ListPreference>(defaultValue, title, summary) {
145+
val titlesResourceId: Int, val valuesResourceId: Int) : Pref<Int, ListPreference, String>(defaultValue, title, summary) {
144146
override fun save(sharedPreferences: SharedPreferences, value: Int) {
145147
sharedPreference.edit().putString(key(), value.toString()).apply()
146148
}
147149

148-
override fun parseDefaultValue(value: Int): String {
150+
override fun toPrefValue(value: Int): String {
149151
return value.toString()
150152
}
151153

154+
override fun fromPrefValue(prefValue: String): Int {
155+
return prefValue.toInt()
156+
}
157+
152158
override fun createPref(context: Context): ListPreference {
153159
val listPreference = ListPreference(context)
154160
listPreference.setEntries(titlesResourceId)

app/src/main/java/nl/giejay/android/tv/immich/shared/prefs/PreferenceManager.kt

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import kotlin.reflect.KClass
99
object PreferenceManager {
1010
lateinit var sharedPreference: SharedPreferences
1111
private lateinit var liveSharedPreferences: LiveSharedPreferences
12-
private val liveContext: MutableMap<String, Any> = mutableMapOf()
12+
// stores the typed values, not the internal PrefTypes (String, Int)
13+
private val liveContext: MutableMap<String, Any?> = mutableMapOf()
1314

1415
fun <T : Any> subclasses(clazz: KClass<T>): List<KClass<out T>> {
1516
return clazz.sealedSubclasses.flatMap { subclasses(it) + it }
@@ -19,27 +20,27 @@ object PreferenceManager {
1920
sharedPreference = PreferenceManager.getDefaultSharedPreferences(context)
2021
liveSharedPreferences = LiveSharedPreferences(sharedPreference)
2122
subclasses(Pref::class).filter { it.objectInstance != null }.forEach { pref ->
22-
val prefInstance = pref.objectInstance!!
23-
liveSharedPreferences.subscribe(prefInstance.key(), prefInstance.defaultValue as Any) { value ->
24-
if (prefInstance.defaultValue is Int) {
25-
liveContext[prefInstance.key()] = value.toString().toInt()
26-
} else {
27-
liveContext[prefInstance.key()] = value
28-
}
23+
val prefInstance = pref.objectInstance!! as Pref<Any, *, *>
24+
liveSharedPreferences.subscribeTyped(prefInstance) { typeValue ->
25+
liveContext[prefInstance.key()] = typeValue
2926
}
3027
}
3128
}
3229

3330
@Suppress("UNCHECKED_CAST")
34-
fun <T> get(key: Pref<T, *>): T {
35-
return key.parse(liveContext[key.key()])
31+
fun <T> get(key: Pref<T, *, *>): T {
32+
return liveContext[key.key()] as T
3633
}
3734

38-
fun <T> save(key: Pref<T, *>, value: T) {
39-
liveContext[key.key()] = value as Any
35+
fun <T, PREFTYPE> save(key: Pref<T, *, PREFTYPE>, value: T) {
36+
liveContext[key.key()] = value
4037
key.save(sharedPreference, value)
4138
}
4239

40+
fun <T> subscribe(key: Pref<T, *, *>, onChange: (T) -> Unit){
41+
liveSharedPreferences.subscribeTyped(key, onChange)
42+
}
43+
4344
fun isLoggedId(): Boolean {
4445
return isValid(get(HOST_NAME), get(API_KEY))
4546
}
@@ -53,29 +54,6 @@ object PreferenceManager {
5354
API_KEY.save(sharedPreference, "")
5455
}
5556

56-
fun saveSortingForAlbum(albumId: String, value: String) {
57-
saveString(keyAlbumsSorting(albumId), value)
58-
}
59-
60-
fun getSortingForAlbum(albumId: String): PhotosOrder {
61-
return PhotosOrder.valueOfSafe(
62-
getString(keyAlbumsSorting(albumId), get(PHOTOS_SORTING).toString()),
63-
get(PHOTOS_SORTING)
64-
)
65-
}
66-
67-
private fun saveString(key: String, value: String) {
68-
sharedPreference.edit().putString(key, value).apply()
69-
}
70-
71-
private fun getString(key: String, default: String): String {
72-
return sharedPreference.getString(key, default)!!
73-
}
74-
75-
fun keyAlbumsSorting(albumId: String): String {
76-
return "photos_sorting_${albumId}"
77-
}
78-
7957
private fun removeStringSetItem(item: String, prefKey: StringSetPref) {
8058
save(prefKey, get(prefKey).filter { it != item }.toSet())
8159
}
@@ -95,4 +73,8 @@ object PreferenceManager {
9573
fun itemInStringSet(name: String?, prefKey: StringSetPref): Boolean {
9674
return name?.let { get(prefKey).contains(it) } ?: false
9775
}
76+
77+
fun getString(key: String, default: String): String {
78+
return sharedPreference.getString(key, default)!!
79+
}
9880
}

0 commit comments

Comments
 (0)