-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7c01ebb
commit 89c235a
Showing
25 changed files
with
1,095 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Storage | ||
> Everything here is under construction, be-aware |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
plugins { | ||
id("toolkit-android-library") | ||
id("toolkit-publish") | ||
} | ||
|
||
android.namespace = "br.com.arch.toolkit.storage" | ||
|
||
dependencies { | ||
// JetBrains | ||
implementation(libraries.jetbrains.stdlib.jdk8) | ||
implementation(libraries.jetbrains.coroutines.core) | ||
|
||
// Androidx | ||
implementation(libraries.androidx.security) | ||
implementation(libraries.androidx.startup) | ||
|
||
// Tools | ||
implementation(libraries.square.timber) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle.kts. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools"> | ||
|
||
<application> | ||
<provider | ||
android:name="androidx.startup.InitializationProvider" | ||
android:authorities="${applicationId}.androidx-startup" | ||
android:exported="false" | ||
tools:node="merge"> | ||
<meta-data | ||
android:name="br.com.arch.toolkit.storage.StorageInitializer" | ||
android:value="androidx.startup" /> | ||
</provider> | ||
</application> | ||
|
||
</manifest> |
50 changes: 50 additions & 0 deletions
50
toolkit/storage/src/main/kotlin/br/com/arch/toolkit/storage/KeyValueStorage.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package br.com.arch.toolkit.storage | ||
|
||
/** | ||
* This code defines an interface called KeyValueLocalStorage in Kotlin, which outlines a contract for storing and retrieving key-value pairs in a local storage system. Let's break down its components: | ||
* <br> | ||
* ## Properties | ||
* - type: A property of type StorageType (not shown here) indicating the underlying storage mechanism (e.g., SharedPreferences, DataStore, etc.). | ||
* - name: A property of a String representing the name or identifier of this storage instance. | ||
* <br> | ||
* ## Methods | ||
* - get(key: String): Retrieves the value associated with the given key. Returns null if the key doesn't exist. | ||
* - get(key: String, default: T): Retrieves the value associated with the given key. Returns the provided default value if the key doesn't exist. | ||
* - set(key: String, value: T?): Stores the given value under the specified key. The value can be nullable. | ||
* - remove(key: String): Removes the key-value pair associated with the given key. | ||
* - remove(regex: Regex): Removes all key-value pairs whose keys match the provided regular expression regex. | ||
* - clear(): Removes all key-value pairs from the storage. | ||
* - contains(key: String): Returns true if the storage contains a value for the given key, and false otherwise. | ||
* - size(): Returns the number of key-value pairs currently stored. | ||
* - keys(): Returns a Set containing all the keys present in the storage. | ||
* <br> | ||
* ## Purpose | ||
* This interface provides a standardized way to interact with different local storage solutions in your Android application. By implementing this interface, you can create concrete storage classes (e.g., SharedPreferencesStorage, DataStoreStorage) that handle the actual storage logic while adhering to a common API. | ||
* <br> | ||
* This abstraction allows you to easily switch between storage implementations or use multiple storage mechanisms within your app without changing the code that interacts with the storage. | ||
*/ | ||
interface KeyValueStorage { | ||
|
||
val type: StorageType | ||
|
||
val name: String | ||
|
||
fun <T> get(key: String): T? | ||
|
||
fun <T> get(key: String, default: T): T | ||
|
||
fun <T> set(key: String, value: T?) | ||
|
||
fun remove(key: String) | ||
|
||
fun remove(regex: Regex) | ||
|
||
fun clear() | ||
|
||
fun contains(key: String): Boolean | ||
|
||
fun size(): Int | ||
|
||
fun keys(): List<String> | ||
|
||
} |
118 changes: 118 additions & 0 deletions
118
toolkit/storage/src/main/kotlin/br/com/arch/toolkit/storage/StorageCreator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package br.com.arch.toolkit.storage | ||
|
||
import android.content.Context | ||
import br.com.arch.toolkit.storage.impl.EncryptedSharedPrefStorage | ||
import br.com.arch.toolkit.storage.impl.MemoryStorage | ||
import br.com.arch.toolkit.storage.impl.SharedPrefStorage | ||
import kotlin.time.Duration | ||
import kotlin.time.Duration.Companion.milliseconds | ||
|
||
/** | ||
* The provided code defines an object named StorageCreator in Kotlin, which serves as a factory and manager for different types of storage mechanisms. | ||
* | ||
* ## Usage | ||
* Before using the encryptedSharedPref or sharedPref properties, you must call the init() method and provide an Android Context. This initializes the underlying storage instances. | ||
* The createKeyValueStorage() methods provide a convenient way to create different types of storage instances based on your needs. | ||
* | ||
* ## Example | ||
* ```kotlin | ||
* // Initialize the storage creator | ||
* StorageCreator.init(context) | ||
* | ||
* // Access the encrypted shared preferences storage | ||
* val encryptedStorage = StorageCreator.encryptedSharedPref | ||
* | ||
* // Create a memory storage instance | ||
* val memoryStorage = StorageCreator.createKeyValueStorage("temp", StorageType.MEMORY) | ||
* ``` | ||
*/ | ||
object StorageCreator { | ||
|
||
/** | ||
* A nullable property to hold an instance of EncryptedSharedPrefStorage. It's initialized to null and later assigned a value within the init() method. | ||
*/ | ||
private var _encryptedSharedPref: EncryptedSharedPrefStorage? = null | ||
|
||
/** | ||
* Similar to _encryptedSharedPref, it stores an instance of SharedPrefStorage. | ||
*/ | ||
private var _sharedPref: SharedPrefStorage? = null | ||
|
||
/** | ||
* A property representing a time duration, initialized to 300 milliseconds. It can be modified using the setDefaultThreshold() method. | ||
*/ | ||
internal var defaultThreshold: Duration = 300.milliseconds | ||
private set | ||
|
||
/** | ||
* A property representing a function that returns an instance of KeyValueStorage. | ||
* It's initialized to a function that returns an instance of encryptedSharedPref. | ||
*/ | ||
internal var defaultStorage: () -> KeyValueStorage = { encryptedSharedPref } | ||
private set | ||
|
||
/** | ||
* An instance of MemoryStorage with the name "default", likely used for temporary in-memory data storage. | ||
*/ | ||
val memory = MemoryStorage("default") | ||
|
||
/** | ||
* A computed property that provides access to the _encryptedSharedPref instance. It throws an exception if accessed before initialization. | ||
*/ | ||
val encryptedSharedPref: EncryptedSharedPrefStorage | ||
get() = requireNotNull(_encryptedSharedPref) { | ||
"Not initialized, Be aware to call init() before use" | ||
} | ||
|
||
/** | ||
* Similar to encryptedSharedPref, it provides access to the _sharedPref instance, ensuring it's initialized. | ||
*/ | ||
val sharedPref: EncryptedSharedPrefStorage | ||
get() = requireNotNull(_encryptedSharedPref) { | ||
"Not initialized, Be aware to call init() before use" | ||
} | ||
|
||
/** | ||
* This function initializes the _encryptedSharedPref and _sharedPref properties using the provided Android Context. It's crucial to call this method before accessing these storage instances. | ||
*/ | ||
fun init(context: Context) { | ||
_encryptedSharedPref = EncryptedSharedPrefStorage(context, "default") | ||
_sharedPref = SharedPrefStorage(context, "default") | ||
} | ||
|
||
/** | ||
* A factory method that creates and returns a storage instance based on the specified StorageType. | ||
* It supports only MemoryStorage | ||
*/ | ||
fun createKeyValueStorage(name: String, type: StorageType) = | ||
when (type) { | ||
StorageType.MEMORY -> MemoryStorage(name) | ||
StorageType.ENCRYPTED_SHARED_PREF -> error("To create this type of storage, you must provide a context") | ||
StorageType.SHARED_PREF -> error("To create this type of storage, you must provide a context") | ||
} | ||
|
||
/** | ||
* A factory method that creates and returns a storage instance based on the specified StorageType. | ||
* It supports MemoryStorage, EncryptedSharedPrefStorage, and SharedPrefStorage. | ||
*/ | ||
fun createKeyValueStorage(context: Context, name: String, type: StorageType) = | ||
when (type) { | ||
StorageType.MEMORY -> MemoryStorage(name) | ||
StorageType.ENCRYPTED_SHARED_PREF -> EncryptedSharedPrefStorage(context, name) | ||
StorageType.SHARED_PREF -> SharedPrefStorage(context, name) | ||
} | ||
|
||
/** | ||
* Allows modification of the defaultThreshold property. | ||
*/ | ||
fun setDefaultThreshold(threshold: Duration) { | ||
defaultThreshold = threshold | ||
} | ||
|
||
/** | ||
* Allows modification of the defaultStorage property. | ||
*/ | ||
fun setDefaultStorage(storage: () -> KeyValueStorage) { | ||
defaultStorage = storage | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
toolkit/storage/src/main/kotlin/br/com/arch/toolkit/storage/StorageInitializer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package br.com.arch.toolkit.storage | ||
|
||
import android.content.Context | ||
import androidx.startup.Initializer | ||
|
||
internal class StorageInitializer : Initializer<Unit> { | ||
override fun create(context: Context) = StorageCreator.init(context) | ||
override fun dependencies() = mutableListOf<Class<out Initializer<*>>>() | ||
} |
23 changes: 23 additions & 0 deletions
23
toolkit/storage/src/main/kotlin/br/com/arch/toolkit/storage/StorageType.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package br.com.arch.toolkit.storage | ||
|
||
/** | ||
* This Kotlin code defines an enum class named StorageType. | ||
* In this case, StorageType represents different ways to store data in an Android app | ||
*/ | ||
enum class StorageType { | ||
|
||
/** | ||
* This likely refers to storing data in the device's RAM, which is temporary and will be lost when the app closes. | ||
*/ | ||
MEMORY, | ||
|
||
/** | ||
* This likely refers to storing data in the device's RAM, which is temporary and will be lost when the app closes. | ||
*/ | ||
SHARED_PREF, | ||
|
||
/** | ||
* This suggests a more secure way of using SharedPreferences, likely employing encryption to protect the stored data. | ||
*/ | ||
ENCRYPTED_SHARED_PREF; | ||
} |
37 changes: 37 additions & 0 deletions
37
toolkit/storage/src/main/kotlin/br/com/arch/toolkit/storage/delegate/_base.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package br.com.arch.toolkit.storage.delegate | ||
|
||
import br.com.arch.toolkit.storage.KeyValueStorage | ||
import br.com.arch.toolkit.storage.util.ThresholdData | ||
import timber.log.Timber | ||
import kotlin.time.Duration | ||
|
||
|
||
open class BaseStorageDelegate<T> internal constructor( | ||
private val name: () -> String, | ||
private val default: (() -> T)?, | ||
private val storage: () -> KeyValueStorage, | ||
threshold: Duration, | ||
) { | ||
|
||
protected val lastAccess = ThresholdData<T>(threshold) | ||
|
||
protected fun name() = name.runCatching { invoke().takeIf { it.isNotBlank() } } | ||
.onFailure { it.log("[Storage] Failed to get name for key value storage") } | ||
.getOrNull() | ||
|
||
protected fun storage() = storage.runCatching { invoke() } | ||
.onFailure { it.log("[Storage] Failed to get storage for key value storage") } | ||
.getOrNull() | ||
|
||
protected fun default() = default.runCatching { requireNotNull(this).invoke() } | ||
.onFailure { it.log("[Storage] Failed to get default value for ${name()}") } | ||
.getOrThrow() | ||
|
||
private fun Throwable.log(message: String) { | ||
Timber.tag("Storage Delegate").e(this, message) | ||
} | ||
|
||
protected fun log(message: String) { | ||
Timber.tag("Storage Delegate").i(message) | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
...kit/storage/src/main/kotlin/br/com/arch/toolkit/storage/delegate/_primitiveNonOptional.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package br.com.arch.toolkit.storage.delegate | ||
|
||
import br.com.arch.toolkit.storage.KeyValueStorage | ||
import br.com.arch.toolkit.storage.StorageCreator | ||
import kotlin.properties.ReadWriteProperty | ||
import kotlin.reflect.KProperty | ||
import kotlin.time.Duration | ||
|
||
fun <T : Any> keyValueStorage( | ||
name: String, | ||
default: T, | ||
storage: () -> KeyValueStorage = StorageCreator.defaultStorage, | ||
duration: Duration = StorageCreator.defaultThreshold | ||
) = keyValueStorage( | ||
name = { name }, | ||
default = { default }, | ||
storage = storage, | ||
duration = duration | ||
) | ||
|
||
fun <T : Any> keyValueStorage( | ||
name: String, | ||
default: () -> T, | ||
storage: () -> KeyValueStorage = StorageCreator.defaultStorage, | ||
duration: Duration = StorageCreator.defaultThreshold | ||
) = keyValueStorage( | ||
name = { name }, | ||
default = default, | ||
storage = storage, | ||
duration = duration | ||
) | ||
|
||
fun <T : Any> keyValueStorage( | ||
name: () -> String, | ||
default: () -> T, | ||
storage: () -> KeyValueStorage = StorageCreator.defaultStorage, | ||
duration: Duration = StorageCreator.defaultThreshold | ||
) = PrimitiveStorageDelegate( | ||
name = name, | ||
default = default, | ||
threshold = duration, | ||
storage = storage | ||
) | ||
|
||
class PrimitiveStorageDelegate<T> internal constructor( | ||
name: () -> String, | ||
default: () -> T, | ||
storage: () -> KeyValueStorage, | ||
threshold: Duration, | ||
) : BaseStorageDelegate<T>( | ||
name = name, | ||
default = default, | ||
storage = storage, | ||
threshold = threshold | ||
), ReadWriteProperty<Any?, T> { | ||
|
||
private var savedData: T? by keyValueStorage( | ||
name = name, | ||
storage = storage, | ||
threshold = threshold | ||
) | ||
|
||
override operator fun getValue(thisRef: Any?, property: KProperty<*>): T = savedData ?: default().also { | ||
log("Delivering default value for ${property.name}") | ||
} | ||
|
||
override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { | ||
savedData = value | ||
} | ||
} |
Oops, something went wrong.