Skip to content

Commit 132eae1

Browse files
authored
Merge pull request #17 from Javernaut/refactoring/default_shared_preferences_to_datastore
Using DataStore instead of default SharedPreferences
2 parents 98c15c1 + a90e1ac commit 132eae1

29 files changed

+544
-506
lines changed

app/src/main/java/com/javernaut/whatthecodec/compose/common/GridLayout.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.compose.ui.layout.Layout
66
import androidx.compose.ui.unit.Constraints
77
import androidx.compose.ui.unit.Dp
88
import androidx.compose.ui.unit.dp
9+
import kotlin.math.max
910
import kotlin.math.nextUp
1011
import kotlin.math.roundToInt
1112

@@ -39,10 +40,10 @@ fun GridLayout(
3940
val maxHeights = chunkedPlacables.map { it.maxByOrNull { it.height }!!.height }
4041
val maxWidth = chunkedPlacables.maxOf { it.sumOf { it.width } }
4142
val dstHeight = maxHeights.sum() + totalVerticalSpacing
42-
val dstWidth = maxWidth + totalVerticalSpacing
43+
val dstWidth = maxWidth + totalHorizontalSpacing
4344

4445
var runningY = 0
45-
layout(dstWidth, dstHeight) {
46+
layout(max(dstWidth, constraints.minWidth), dstHeight) {
4647
chunkedPlacables.forEachIndexed { index, list ->
4748
var runningX = 0
4849
list.forEach {

app/src/main/java/com/javernaut/whatthecodec/compose/preference/ListPreference.kt

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.javernaut.whatthecodec.compose.preference
22

3-
import android.preference.PreferenceManager
43
import androidx.compose.animation.AnimatedVisibility
54
import androidx.compose.animation.fadeIn
65
import androidx.compose.animation.fadeOut
@@ -30,7 +29,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
3029
import androidx.compose.runtime.setValue
3130
import androidx.compose.ui.Alignment
3231
import androidx.compose.ui.Modifier
33-
import androidx.compose.ui.platform.LocalContext
3432
import androidx.compose.ui.res.stringResource
3533
import androidx.compose.ui.unit.dp
3634
import com.javernaut.whatthecodec.R
@@ -95,49 +93,45 @@ fun SingleChoicePreferenceDialog(
9593

9694
@Composable
9795
fun MultiSelectListPreference(
98-
key: String,
99-
defaultValue: Set<String>,
10096
title: String,
101-
displayableEntries: List<String>,
102-
entriesCodes: List<String>,
103-
summaryBuilder: (List<String>) -> String = { it.joinToString() },
104-
onNewCodeSelected: ((Set<String>) -> Unit)? = null
97+
items: List<String>,
98+
currentlySelectedIndexes: Collection<Int>,
99+
onNewCodeSelected: ((Collection<Int>) -> Unit) = { }
105100
) {
106-
val applicationContext = LocalContext.current.applicationContext
107-
val defaultSharedPreferences =
108-
PreferenceManager.getDefaultSharedPreferences(applicationContext)
109-
val selectedItemCodes = defaultSharedPreferences.getStringSet(key, defaultValue)!!
110-
val currentlySelectedItemIndexes = List(displayableEntries.size) {
111-
selectedItemCodes.contains(entriesCodes[it])
112-
}
113-
114101
var dialogOpened by rememberSaveable { mutableStateOf(false) }
115-
Preference(
116-
title = title,
117-
summary = summaryBuilder(displayableEntries.filterIndexed { index, s ->
118-
currentlySelectedItemIndexes[index]
119-
}).ifEmpty {
102+
103+
val summary = items.filterIndexed { index, _ ->
104+
currentlySelectedIndexes.contains(index)
105+
}.joinToString()
106+
.ifEmpty {
120107
stringResource(id = R.string.settings_nothing_is_selected)
121108
}
109+
110+
Preference(
111+
title = title,
112+
summary = summary
122113
) {
123114
dialogOpened = true
124115
}
125116

126117
if (dialogOpened) {
118+
val initialSelectedPositions = List(items.size) {
119+
currentlySelectedIndexes.contains(it)
120+
}
121+
127122
MultiChoicePreferenceDialog(
128123
title = title,
129124
onDismissRequest = { dialogOpened = false },
130-
items = displayableEntries,
131-
initialSelectedPositions = currentlySelectedItemIndexes
125+
items = items,
126+
initialSelectedPositions = initialSelectedPositions
132127
) { resultList ->
133-
val newValueToSet = entriesCodes.filterIndexed { index, s ->
134-
resultList[index]
135-
}.toSet()
136-
defaultSharedPreferences
137-
.edit()
138-
.putStringSet(key, newValueToSet)
139-
.apply()
140-
onNewCodeSelected?.invoke(newValueToSet)
128+
onNewCodeSelected(mutableSetOf<Int>().also { set ->
129+
resultList.forEachIndexed { index, item ->
130+
if (item) {
131+
set.add(index)
132+
}
133+
}
134+
})
141135
}
142136
}
143137
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.javernaut.whatthecodec.home.data
2+
3+
import androidx.datastore.core.DataStore
4+
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.edit
6+
import kotlinx.coroutines.flow.Flow
7+
import kotlinx.coroutines.flow.map
8+
import java.util.EnumSet
9+
10+
internal inline fun <reified E : Enum<E>> DataStore<Preferences>.enumSetFlow(
11+
key: Preferences.Key<Set<String>>
12+
): Flow<Set<E>> = data.map {
13+
it[key]?.mapTo(
14+
// Mapping into an EnumSet, as more efficient set implementation for enums
15+
mutableEnumSet()
16+
) {
17+
enumValueOf(it)
18+
}
19+
// If nothing is present in DataStore, we treat it as 'everything is enabled'
20+
?: completeEnumSet()
21+
}
22+
23+
internal suspend fun DataStore<Preferences>.saveEnumSet(
24+
key: Preferences.Key<Set<String>>,
25+
enumSet: Set<Any>
26+
) {
27+
edit { settings ->
28+
settings[key] = enumSet.mapTo(
29+
mutableSetOf()
30+
) {
31+
it.toString()
32+
}
33+
}
34+
}
35+
36+
internal inline fun <reified E : Enum<E>> mutableEnumSet(): EnumSet<E> {
37+
return EnumSet.noneOf(E::class.java)
38+
}
39+
40+
internal inline fun <reified E : Enum<E>> completeEnumSet(): EnumSet<E> {
41+
return EnumSet.allOf(E::class.java)
42+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.javernaut.whatthecodec.home.data
2+
3+
import android.content.Context
4+
import androidx.datastore.core.DataStore
5+
import androidx.datastore.preferences.core.Preferences
6+
import androidx.datastore.preferences.core.stringSetPreferencesKey
7+
import androidx.datastore.preferences.preferencesDataStore
8+
import com.javernaut.whatthecodec.home.data.model.AudioStreamFeature
9+
import com.javernaut.whatthecodec.home.data.model.SubtitleStreamFeature
10+
import com.javernaut.whatthecodec.home.data.model.VideoStreamFeature
11+
import dagger.hilt.android.qualifiers.ApplicationContext
12+
import kotlinx.coroutines.flow.Flow
13+
import javax.inject.Inject
14+
import javax.inject.Singleton
15+
16+
@Singleton
17+
class StreamFeatureRepository @Inject constructor(
18+
@ApplicationContext context: Context
19+
) {
20+
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "stream_features")
21+
22+
private val dataStore = context.dataStore
23+
24+
private val keyVideoStreamFeatures = stringSetPreferencesKey("video_stream_features")
25+
private val keyAudioStreamFeatures = stringSetPreferencesKey("audio_stream_features")
26+
private val keySubtitleStreamFeatures = stringSetPreferencesKey("subtitle_stream_features")
27+
28+
val videoStreamFeatures: Flow<Set<VideoStreamFeature>> =
29+
context.dataStore.enumSetFlow(
30+
keyVideoStreamFeatures
31+
)
32+
33+
val audioStreamFeatures: Flow<Set<AudioStreamFeature>> =
34+
context.dataStore.enumSetFlow(
35+
keyAudioStreamFeatures
36+
)
37+
38+
val subtitleStreamFeatures: Flow<Set<SubtitleStreamFeature>> =
39+
context.dataStore.enumSetFlow(
40+
keySubtitleStreamFeatures
41+
)
42+
43+
44+
suspend fun setVideoStreamFeatures(newVideoStreamFeatures: Set<VideoStreamFeature>) {
45+
dataStore.saveEnumSet(keyVideoStreamFeatures, newVideoStreamFeatures)
46+
}
47+
48+
suspend fun setAudioStreamFeatures(newAudioStreamFeatures: Set<AudioStreamFeature>) {
49+
dataStore.saveEnumSet(keyAudioStreamFeatures, newAudioStreamFeatures)
50+
}
51+
52+
suspend fun setSubtitleStreamFeatures(newSubtitleStreamFeatures: Set<SubtitleStreamFeature>) {
53+
dataStore.saveEnumSet(keySubtitleStreamFeatures, newSubtitleStreamFeatures)
54+
}
55+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.javernaut.whatthecodec.home.data.model
2+
3+
import androidx.annotation.Keep
4+
5+
@Keep
6+
enum class AudioStreamFeature {
7+
Codec,
8+
Bitrate,
9+
Channels,
10+
ChannelLayout,
11+
SampleFormat,
12+
SampleRate,
13+
Language,
14+
Disposition
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.javernaut.whatthecodec.home.data.model
2+
3+
import androidx.annotation.Keep
4+
5+
@Keep
6+
enum class SubtitleStreamFeature {
7+
Codec,
8+
Language,
9+
Disposition
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.javernaut.whatthecodec.home.data.model
2+
3+
import androidx.annotation.Keep
4+
5+
@Keep
6+
enum class VideoStreamFeature {
7+
Codec,
8+
Bitrate,
9+
FrameRate,
10+
FrameWidth,
11+
FrameHeight,
12+
Language,
13+
Disposition
14+
}

0 commit comments

Comments
 (0)