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