shared preferences api
This commit is contained in:
-10
@@ -1,10 +0,0 @@
|
||||
package expo.modules.blueskyswissarmy.deviceprefs
|
||||
|
||||
import expo.modules.kotlin.modules.Module
|
||||
import expo.modules.kotlin.modules.ModuleDefinition
|
||||
|
||||
class ExpoBlueskyDevicePrefsModule : Module() {
|
||||
override fun definition() = ModuleDefinition {
|
||||
Name("ExpoBlueskyDevicePrefs")
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package expo.modules.blueskyswissarmy.sharedprefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import expo.modules.kotlin.Promise
|
||||
import expo.modules.kotlin.jni.JavaScriptValue
|
||||
import expo.modules.kotlin.modules.Module
|
||||
import expo.modules.kotlin.modules.ModuleDefinition
|
||||
|
||||
class ExpoBlueskySharedPrefsModule : Module() {
|
||||
private fun getContext(): Context {
|
||||
val context = appContext.reactContext ?: throw Error("Context is null")
|
||||
return context
|
||||
}
|
||||
|
||||
override fun definition() = ModuleDefinition {
|
||||
Name("ExpoBlueskySharedPrefs")
|
||||
|
||||
AsyncFunction("setStringAsync") { key: String, value: String ->
|
||||
return@AsyncFunction Preferences(getContext()).setValue(key, value)
|
||||
}
|
||||
|
||||
AsyncFunction("setValueAsync") { key: String, value: JavaScriptValue, promise: Promise ->
|
||||
val context = getContext()
|
||||
try {
|
||||
if (value.isNumber()) {
|
||||
Preferences(context).setValue(key, value.getFloat())
|
||||
promise.resolve()
|
||||
} else if (value.isBool()) {
|
||||
Preferences(context).setValue(key, value.getBool())
|
||||
promise.resolve()
|
||||
} else if (value.isNull() || value.isUndefined()) {
|
||||
Preferences(context).removeValue(key)
|
||||
promise.resolve()
|
||||
} else {
|
||||
Log.d(NAME, "Unsupported type: ${value.kind()}")
|
||||
promise.reject("UNSUPPORTED_TYPE_ERROR", "Attempted to set an unsupported type", null)
|
||||
}
|
||||
} catch (e: Error) {
|
||||
Log.d(NAME, "Error setting value: $e")
|
||||
promise.reject("SET_VALUE_ERROR", "Error setting value", e)
|
||||
}
|
||||
}
|
||||
|
||||
AsyncFunction("removeValueAsync") { key: String ->
|
||||
return@AsyncFunction Preferences(getContext()).removeValue(key)
|
||||
}
|
||||
|
||||
AsyncFunction("getStringAsync") { key: String ->
|
||||
return@AsyncFunction Preferences(getContext()).getString(key)
|
||||
}
|
||||
|
||||
AsyncFunction("getNumberAsync") { key: String ->
|
||||
return@AsyncFunction Preferences(getContext()).getFloat(key)
|
||||
}
|
||||
|
||||
AsyncFunction("getBoolAsync") { key: String ->
|
||||
return@AsyncFunction Preferences(getContext()).getBoolean(key)
|
||||
}
|
||||
|
||||
AsyncFunction("addToSetAsync") { key: String, value: String ->
|
||||
return@AsyncFunction Preferences(getContext()).addToSet(key, value)
|
||||
}
|
||||
|
||||
AsyncFunction("removeFromSetAsync") { key: String, value: String ->
|
||||
return@AsyncFunction Preferences(getContext()).removeFromSet(key, value)
|
||||
}
|
||||
|
||||
AsyncFunction("setContainsAsync") { key: String, value: String ->
|
||||
return@AsyncFunction Preferences(getContext()).setContains(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
package expo.modules.blueskyswissarmy.sharedprefs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
|
||||
val DEFAULTS = mapOf<String, Any>(
|
||||
"playSoundChat" to true,
|
||||
"playSoundFollow" to false,
|
||||
"playSoundLike" to false,
|
||||
"playSoundMention" to false,
|
||||
"playSoundQuote" to false,
|
||||
"playSoundReply" to false,
|
||||
"playSoundRepost" to false,
|
||||
"badgeCount" to 0,
|
||||
)
|
||||
|
||||
const val NAME = "SharedPrefs"
|
||||
|
||||
class Preferences(private val context: Context) {
|
||||
companion object {
|
||||
private var hasInitialized = false
|
||||
|
||||
private var instance: SharedPreferences? = null
|
||||
|
||||
fun getInstance(context: Context, info: String? = "(no info)"): SharedPreferences {
|
||||
if (instance == null) {
|
||||
Log.d(NAME, "No preferences instance found, creating one.")
|
||||
instance = context.getSharedPreferences("xyz.blueskyweb.app", Context.MODE_PRIVATE)
|
||||
}
|
||||
|
||||
val safeInstance = instance ?: throw Error("Preferences is null: $info")
|
||||
|
||||
if (!hasInitialized) {
|
||||
Log.d(NAME, "Preferences instance has not been initialized yet.")
|
||||
initialize(safeInstance)
|
||||
hasInitialized = true
|
||||
Log.d(NAME, "Preferences instance has been initialized.")
|
||||
}
|
||||
|
||||
return safeInstance
|
||||
}
|
||||
|
||||
private fun initialize(instance: SharedPreferences) {
|
||||
instance
|
||||
.edit()
|
||||
.apply {
|
||||
DEFAULTS.forEach { (key, value) ->
|
||||
if (instance.contains(key)) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
when (value) {
|
||||
is Boolean -> {
|
||||
putBoolean(key, value)
|
||||
}
|
||||
|
||||
is String -> {
|
||||
putString(key, value)
|
||||
}
|
||||
|
||||
is Array<*> -> {
|
||||
putStringSet(key, value.map { it.toString() }.toSet())
|
||||
}
|
||||
|
||||
is Map<*, *> -> {
|
||||
putStringSet(key, value.map { it.toString() }.toSet())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.apply()
|
||||
}
|
||||
}
|
||||
|
||||
fun setValue(key: String, value: String) {
|
||||
val safeInstance = getInstance(context)
|
||||
safeInstance.edit().apply {
|
||||
putString(key, value)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun setValue(key: String, value: Float) {
|
||||
val safeInstance = getInstance(context)
|
||||
safeInstance.edit().apply {
|
||||
putFloat(key, value)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun setValue(key: String, value: Boolean) {
|
||||
val safeInstance = getInstance(context)
|
||||
safeInstance.edit().apply {
|
||||
putBoolean(key, value)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun setValue(key: String, value: Set<String>) {
|
||||
val safeInstance = getInstance(context)
|
||||
safeInstance.edit().apply {
|
||||
putStringSet(key, value)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun removeValue(key: String) {
|
||||
val safeInstance = getInstance(context)
|
||||
safeInstance.edit().apply {
|
||||
remove(key)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun getString(key: String): String? {
|
||||
val safeInstance = getInstance(context)
|
||||
return safeInstance.getString(key, null)
|
||||
}
|
||||
|
||||
fun getFloat(key: String): Float? {
|
||||
val safeInstance = getInstance(context)
|
||||
if (!safeInstance.contains(key)) {
|
||||
return null
|
||||
}
|
||||
return safeInstance.getFloat(key, 0.0f)
|
||||
}
|
||||
|
||||
fun getBoolean(key: String): Boolean? {
|
||||
val safeInstance = getInstance(context)
|
||||
if (!safeInstance.contains(key)) {
|
||||
return null
|
||||
}
|
||||
Log.d(NAME, "Getting boolean for key: $key")
|
||||
val res = safeInstance.getBoolean(key, false)
|
||||
Log.d(NAME, "Got boolean for key: $key, value: $res")
|
||||
return res
|
||||
}
|
||||
|
||||
fun addToSet(key: String, value: String) {
|
||||
val safeInstance = getInstance(context)
|
||||
val set = safeInstance.getStringSet(key, setOf()) ?: setOf()
|
||||
val newSet = set.toMutableSet().apply {
|
||||
add(value)
|
||||
}
|
||||
safeInstance.edit().apply {
|
||||
putStringSet(key, newSet)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun removeFromSet(key: String, value: String) {
|
||||
val safeInstance = getInstance(context)
|
||||
val set = safeInstance.getStringSet(key, setOf()) ?: setOf()
|
||||
val newSet = set.toMutableSet().apply {
|
||||
remove(value)
|
||||
}
|
||||
safeInstance.edit().apply {
|
||||
putStringSet(key, newSet)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun setContains(key: String, value: String): Boolean {
|
||||
val safeInstance = getInstance(context)
|
||||
val set = safeInstance.getStringSet(key, setOf()) ?: setOf()
|
||||
return set.contains(value)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"platforms": ["ios", "tvos", "android", "web"],
|
||||
"ios": {
|
||||
"modules": ["ExpoBlueskyDevicePrefsModule", "ExpoBlueskyReferrerModule"]
|
||||
"modules": ["ExpoBlueskySharedPrefsModule", "ExpoBlueskyReferrerModule"]
|
||||
},
|
||||
"android": {
|
||||
"modules": [
|
||||
"expo.modules.blueskyswissarmy.deviceprefs.ExpoBlueskyDevicePrefsModule",
|
||||
"expo.modules.blueskyswissarmy.sharedprefs.ExpoBlueskySharedPrefsModule",
|
||||
"expo.modules.blueskyswissarmy.referrer.ExpoBlueskyReferrerModule"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as DevicePrefs from './src/DevicePrefs'
|
||||
import * as Referrer from './src/Referrer'
|
||||
import * as SharedPrefs from './src/SharedPrefs'
|
||||
|
||||
export {DevicePrefs, Referrer}
|
||||
export {Referrer, SharedPrefs}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import ExpoModulesCore
|
||||
|
||||
public class ExpoBlueskyDevicePrefsModule: Module {
|
||||
func getDefaults(_ useAppGroup: Bool) -> UserDefaults? {
|
||||
if useAppGroup {
|
||||
return UserDefaults(suiteName: "group.app.bsky")
|
||||
} else {
|
||||
return UserDefaults.standard
|
||||
}
|
||||
}
|
||||
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("ExpoBlueskyDevicePrefs")
|
||||
|
||||
AsyncFunction("getStringValueAsync") { (key: String, useAppGroup: Bool) in
|
||||
return self.getDefaults(useAppGroup)?.string(forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("setStringValueAsync") { (key: String, value: String?, useAppGroup: Bool) in
|
||||
self.getDefaults(useAppGroup)?.setValue(value, forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import Foundation
|
||||
import ExpoModulesCore
|
||||
|
||||
public class ExpoBlueskySharedPrefsModule: Module {
|
||||
let defaults = UserDefaults(suiteName: "group.app.bsky")
|
||||
|
||||
func getDefaults(_ info: String = "(no info)") -> UserDefaults? {
|
||||
guard let defaults = self.defaults else {
|
||||
NSLog("Failed to get defaults for app group: \(info)")
|
||||
return nil
|
||||
}
|
||||
return defaults
|
||||
}
|
||||
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("ExpoBlueskySharedPrefs")
|
||||
|
||||
AsyncFunction("setValueAsync") { (key: String, value: JavaScriptValue, promise: Promise) in
|
||||
guard value.isString() || value.isNumber() || value.isBool() || value.isNull() || value.isUndefined() else {
|
||||
promise.reject("UNSUPPORTED_TYPE_ERROR", "Attempted to set an unsupported type")
|
||||
return false
|
||||
}
|
||||
|
||||
guard let defaults = self.getDefaults() else {
|
||||
promise.reject("PREFS_ERROR", "Was unable to get shared preferences")
|
||||
return false
|
||||
}
|
||||
|
||||
if value.isNumber() {
|
||||
defaults.set(value.getDouble(), forKey: key)
|
||||
} else {
|
||||
defaults.set(value.getRaw(), forKey: key)
|
||||
}
|
||||
promise.resolve()
|
||||
return true
|
||||
}
|
||||
|
||||
AsyncFunction("removeValueAsync") { (key: String) in
|
||||
self.getDefaults(key)?.removeObject(forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("getStringAsync") { (key: String) in
|
||||
return self.getDefaults(key)?.string(forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("getBoolAsync") { (key: String) in
|
||||
return self.getDefaults(key)?.bool(forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("getNumberAsync") { (key: String) in
|
||||
return self.getDefaults(key)?.double(forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("addToSetAsync") { (key: String, value: String) in
|
||||
var dict: [String:Bool]?
|
||||
if var currDict = self.getDefaults(key)?.dictionary(forKey: key) as? [String:Bool] {
|
||||
currDict[value] = true
|
||||
dict = currDict
|
||||
} else {
|
||||
dict = [
|
||||
value : true
|
||||
]
|
||||
}
|
||||
self.getDefaults(key)?.setValue(dict, forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("removeFromSetAsync") { (key: String, value: String) in
|
||||
guard var dict = self.getDefaults(key)?.dictionary(forKey: key) as? [String:Bool] else {
|
||||
return
|
||||
}
|
||||
dict.removeValue(forKey: value)
|
||||
self.getDefaults(key)?.setValue(dict, forKey: key)
|
||||
}
|
||||
|
||||
AsyncFunction("setContainsAsync") { (key: String, value: String) in
|
||||
guard let dict = self.getDefaults(key)?.dictionary(forKey: key) as? [String:Bool] else {
|
||||
return false
|
||||
}
|
||||
return dict[value] == true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import {requireNativeModule} from 'expo-modules-core'
|
||||
|
||||
const NativeModule = requireNativeModule('ExpoBlueskyDevicePrefs')
|
||||
|
||||
export function getStringValueAsync(
|
||||
key: string,
|
||||
useAppGroup?: boolean,
|
||||
): Promise<string | null> {
|
||||
return NativeModule.getStringValueAsync(key, useAppGroup)
|
||||
}
|
||||
|
||||
export function setStringValueAsync(
|
||||
key: string,
|
||||
value: string | null,
|
||||
useAppGroup?: boolean,
|
||||
): Promise<void> {
|
||||
return NativeModule.setStringValueAsync(key, value, useAppGroup)
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import {NotImplementedError} from '../NotImplemented'
|
||||
|
||||
export function getStringValueAsync(
|
||||
key: string,
|
||||
useAppGroup?: boolean,
|
||||
): Promise<string | null> {
|
||||
throw new NotImplementedError({key, useAppGroup})
|
||||
}
|
||||
|
||||
export function setStringValueAsync(
|
||||
key: string,
|
||||
value: string | null,
|
||||
useAppGroup?: boolean,
|
||||
): Promise<string | null> {
|
||||
throw new NotImplementedError({key, value, useAppGroup})
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import {Platform} from 'react-native'
|
||||
import {requireNativeModule} from 'expo-modules-core'
|
||||
|
||||
const NativeModule = requireNativeModule('ExpoBlueskySharedPrefs')
|
||||
|
||||
export function setValueAsync(
|
||||
key: string,
|
||||
value: string | number | boolean | null | undefined,
|
||||
): Promise<void> {
|
||||
// A bug on Android causes `JavaScripValue.isString()` to cause a crash on some occasions, seemingly because of a
|
||||
// memory violation. Instead, we will use a specific function to set strings on this platform.
|
||||
if (Platform.OS === 'android' && typeof value === 'string') {
|
||||
return NativeModule.setStringAsync(key, value)
|
||||
}
|
||||
return NativeModule.setValueAsync(key, value)
|
||||
}
|
||||
|
||||
export function removeValueAsync(key: string): Promise<void> {
|
||||
return NativeModule.removeValueAsync(key)
|
||||
}
|
||||
|
||||
export function getStringAsync(key: string): Promise<string | null> {
|
||||
return NativeModule.getStringAsync(key)
|
||||
}
|
||||
|
||||
export function getNumberAsync(key: string): Promise<number | null> {
|
||||
return NativeModule.getNumberAsync(key)
|
||||
}
|
||||
|
||||
export function getBoolAsync(key: string): Promise<boolean | null> {
|
||||
return NativeModule.getBoolAsync(key)
|
||||
}
|
||||
|
||||
export function addToSetAsync(key: string, value: string): Promise<void> {
|
||||
return NativeModule.addToSetAsync(key, value)
|
||||
}
|
||||
|
||||
export function removeFromSetAsync(key: string, value: string): Promise<void> {
|
||||
return NativeModule.removeFromSetAsync(key, value)
|
||||
}
|
||||
|
||||
export function setContainsAsync(key: string, value: string): Promise<boolean> {
|
||||
return NativeModule.setContainsAsync(key, value)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import {NotImplementedError} from '../NotImplemented'
|
||||
|
||||
export function setValueAsync(
|
||||
key: string,
|
||||
value: string | number | boolean | null | undefined,
|
||||
): Promise<void> {
|
||||
throw new NotImplementedError({key, value})
|
||||
}
|
||||
|
||||
export function removeValueAsync(key: string): Promise<void> {
|
||||
throw new NotImplementedError({key})
|
||||
}
|
||||
|
||||
export function getStringAsync(key: string): Promise<string | null> {
|
||||
console.log('call')
|
||||
throw new NotImplementedError({key})
|
||||
}
|
||||
|
||||
export function getNumberAsync(key: string): Promise<number | null> {
|
||||
throw new NotImplementedError({key})
|
||||
}
|
||||
|
||||
export function getBoolAsync(key: string): Promise<boolean | null> {
|
||||
throw new NotImplementedError({key})
|
||||
}
|
||||
|
||||
export function addToSetAsync(key: string, value: string): Promise<void> {
|
||||
throw new NotImplementedError({key, value})
|
||||
}
|
||||
|
||||
export function removeFromSetAsync(key: string, value: string): Promise<void> {
|
||||
throw new NotImplementedError({key, value})
|
||||
}
|
||||
|
||||
export function setContainsAsync(key: string, value: string): Promise<boolean> {
|
||||
throw new NotImplementedError({key, value})
|
||||
}
|
||||
Reference in New Issue
Block a user