Skip to content

Commit dac3657

Browse files
pshnicolas-raoul
andauthored
Migrate kvstore to kotlin (commons-app#5973)
* Get good test around the basic KvStore before starting conversion * Converted BasicKvStore to kotlin and removed dead code * Converted JsonKvStore to kotlin --------- Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
1 parent d6c4cab commit dac3657

File tree

10 files changed

+562
-320
lines changed

10 files changed

+562
-320
lines changed

app/src/main/java/fr/free/nrw/commons/auth/SessionManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class SessionManager @Inject constructor(
6262
fun forceLogin(context: Context?) =
6363
context?.let { LoginActivity.startYourself(it) }
6464

65-
fun getPreference(key: String?): Boolean =
65+
fun getPreference(key: String): Boolean =
6666
defaultKvStore.getBoolean(key)
6767

6868
fun logout(): Completable = Completable.fromObservable(

app/src/main/java/fr/free/nrw/commons/kvstore/BasicKvStore.java

Lines changed: 0 additions & 215 deletions
This file was deleted.
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package fr.free.nrw.commons.kvstore
2+
3+
import android.content.Context
4+
import android.content.SharedPreferences
5+
import androidx.annotation.VisibleForTesting
6+
import androidx.core.content.edit
7+
import timber.log.Timber
8+
9+
open class BasicKvStore : KeyValueStore {
10+
/*
11+
This class only performs puts, sets and clears.
12+
A commit returns a boolean indicating whether it has succeeded, we are not throwing an exception as it will
13+
require the dev to handle it in every usage - instead we will pass on this boolean so it can be evaluated if needed.
14+
*/
15+
private val _store: SharedPreferences
16+
17+
constructor(context: Context, storeName: String?) {
18+
_store = context.getSharedPreferences(storeName, Context.MODE_PRIVATE)
19+
}
20+
21+
/**
22+
* If you don't want onVersionUpdate to be called on a fresh creation, the first version supplied for the kvstore should be set to 0.
23+
*/
24+
@JvmOverloads
25+
constructor(
26+
context: Context,
27+
storeName: String?,
28+
version: Int,
29+
clearAllOnUpgrade: Boolean = false
30+
) {
31+
_store = context.getSharedPreferences(storeName, Context.MODE_PRIVATE)
32+
val oldVersion = _store.getInt(KEY_VERSION, 0)
33+
34+
require(version >= oldVersion) {
35+
"kvstore downgrade not allowed, old version:" + oldVersion + ", new version: " +
36+
version
37+
}
38+
39+
if (version > oldVersion) {
40+
Timber.i(
41+
"version updated from %s to %s, with clearFlag %b",
42+
oldVersion,
43+
version,
44+
clearAllOnUpgrade
45+
)
46+
onVersionUpdate(oldVersion, version, clearAllOnUpgrade)
47+
}
48+
49+
//Keep this statement at the end so that clearing of store does not cause version also to get removed.
50+
_store.edit { putInt(KEY_VERSION, version) }
51+
}
52+
53+
val all: Map<String, *>?
54+
get() {
55+
val allContents = _store.all
56+
if (allContents == null || allContents.isEmpty()) {
57+
return null
58+
}
59+
allContents.remove(KEY_VERSION)
60+
return HashMap(allContents)
61+
}
62+
63+
override fun getString(key: String): String? =
64+
getString(key, null)
65+
66+
override fun getBoolean(key: String): Boolean =
67+
getBoolean(key, false)
68+
69+
override fun getLong(key: String): Long =
70+
getLong(key, 0)
71+
72+
override fun getInt(key: String): Int =
73+
getInt(key, 0)
74+
75+
fun getStringSet(key: String?): MutableSet<String> =
76+
_store.getStringSet(key, HashSet())!!
77+
78+
override fun getString(key: String, defaultValue: String?): String? =
79+
_store.getString(key, defaultValue)
80+
81+
override fun getBoolean(key: String, defaultValue: Boolean): Boolean =
82+
_store.getBoolean(key, defaultValue)
83+
84+
override fun getLong(key: String, defaultValue: Long): Long =
85+
_store.getLong(key, defaultValue)
86+
87+
override fun getInt(key: String, defaultValue: Int): Int =
88+
_store.getInt(key, defaultValue)
89+
90+
fun putAllStrings(kvData: Map<String, String>) = assertKeyNotReserved(kvData.keys) {
91+
for ((key, value) in kvData) {
92+
putString(key, value)
93+
}
94+
}
95+
96+
override fun putString(key: String, value: String) = assertKeyNotReserved(key) {
97+
putString(key, value)
98+
}
99+
100+
override fun putBoolean(key: String, value: Boolean) = assertKeyNotReserved(key) {
101+
putBoolean(key, value)
102+
}
103+
104+
override fun putLong(key: String, value: Long) = assertKeyNotReserved(key) {
105+
putLong(key, value)
106+
}
107+
108+
override fun putInt(key: String, value: Int) = assertKeyNotReserved(key) {
109+
putInt(key, value)
110+
}
111+
112+
fun putStringSet(key: String?, value: Set<String?>?) =
113+
_store.edit{ putStringSet(key, value) }
114+
115+
override fun remove(key: String) = assertKeyNotReserved(key) {
116+
remove(key)
117+
}
118+
119+
override fun contains(key: String): Boolean {
120+
if (key == KEY_VERSION) return false
121+
return _store.contains(key)
122+
}
123+
124+
override fun clearAll() {
125+
val version = _store.getInt(KEY_VERSION, 0)
126+
_store.edit {
127+
clear()
128+
putInt(KEY_VERSION, version)
129+
}
130+
}
131+
132+
private fun onVersionUpdate(oldVersion: Int, version: Int, clearAllFlag: Boolean) {
133+
if (clearAllFlag) {
134+
clearAll()
135+
}
136+
}
137+
138+
protected fun assertKeyNotReserved(key: Set<String>, block: SharedPreferences.Editor.() -> Unit) {
139+
key.forEach { require(it != KEY_VERSION) { "$it is a reserved key" } }
140+
_store.edit { block(this) }
141+
}
142+
143+
protected fun assertKeyNotReserved(key: String, block: SharedPreferences.Editor.() -> Unit) {
144+
require(key != KEY_VERSION) { "$key is a reserved key" }
145+
_store.edit { block(this) }
146+
}
147+
148+
companion object {
149+
@VisibleForTesting
150+
const val KEY_VERSION: String = "__version__"
151+
}
152+
}

0 commit comments

Comments
 (0)