Initial commit
This commit is contained in:
46
core/common/build.gradle.kts
Normal file
46
core/common/build.gradle.kts
Normal file
@@ -0,0 +1,46 @@
|
||||
group = "dev.carlosmartino.core"
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.kotlinDevKit)
|
||||
alias(libs.plugins.composeDevKit)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
api(libs.atomicfu)
|
||||
api(libs.kotlinx.datetime)
|
||||
api(libs.kotlinx.coroutines.core)
|
||||
api(libs.kotlinx.serialization.json)
|
||||
api(libs.koin.core)
|
||||
api(libs.koin.compose)
|
||||
api(libs.koin.compose.viewmodel)
|
||||
api(libs.koin.compose.viewmodel.navigation)
|
||||
|
||||
implementation(libs.androidx.security.crypto)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.androidx.datastore.preferences.core)
|
||||
implementation(libs.multiplatform.settings.core)
|
||||
implementation(libs.multiplatform.settings.noarg)
|
||||
implementation(libs.multiplatform.settings.coroutines)
|
||||
implementation(libs.multiplatform.settings.serialization)
|
||||
implementation(libs.moko.permissions)
|
||||
implementation(libs.moko.permissions.compose)
|
||||
implementation(libs.moko.permissions.bluetooth)
|
||||
implementation(libs.moko.permissions.camera)
|
||||
implementation(libs.moko.permissions.contacts)
|
||||
implementation(libs.moko.permissions.gallery)
|
||||
implementation(libs.moko.permissions.location)
|
||||
implementation(libs.moko.permissions.microphone)
|
||||
implementation(libs.moko.permissions.motion)
|
||||
implementation(libs.moko.permissions.notifications)
|
||||
implementation(libs.moko.permissions.storage)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
api(libs.kotlinx.coroutines.android)
|
||||
api(libs.koin.android)
|
||||
api(libs.multiplatform.settings.core)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package cl.homelogic.platform.common
|
||||
|
||||
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
|
||||
actual object Platform {
|
||||
actual fun getType() = PlatformTypes.Android
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cl.homelogic.platform.common.logging
|
||||
|
||||
import android.util.Log
|
||||
|
||||
internal actual fun logPlatform(
|
||||
severity: Severity,
|
||||
tag: String,
|
||||
message: String,
|
||||
) {
|
||||
when (severity) {
|
||||
Severity.Debug -> Log.d(tag, message)
|
||||
Severity.Verbose -> Log.v(tag, message)
|
||||
Severity.Info -> Log.i(tag, message)
|
||||
Severity.Warn -> Log.w(tag, message)
|
||||
Severity.Error -> Log.e(tag, message)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package cl.homelogic.platform.common.settings
|
||||
|
||||
import android.content.Context
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.russhwolf.settings.SharedPreferencesSettings
|
||||
|
||||
class AndroidSettingsFactory(
|
||||
private val context: Context,
|
||||
) : ISettingsFactory {
|
||||
override fun createSettings(name: String?): Settings {
|
||||
val prefName = name ?: "secure_settings"
|
||||
|
||||
val masterKey = MasterKey
|
||||
.Builder(context)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
val sharedPreferences = EncryptedSharedPreferences.create(
|
||||
context,
|
||||
prefName,
|
||||
masterKey,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
|
||||
)
|
||||
|
||||
return SharedPreferencesSettings(sharedPreferences)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package cl.homelogic.platform.common
|
||||
|
||||
enum class PlatformTypes {
|
||||
IOS,
|
||||
Android,
|
||||
}
|
||||
|
||||
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
|
||||
expect object Platform {
|
||||
fun getType(): PlatformTypes
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package cl.homelogic.platform.common.logging
|
||||
|
||||
import kotlinx.atomicfu.locks.SynchronizedObject
|
||||
import kotlinx.atomicfu.locks.synchronized
|
||||
import kotlinx.datetime.TimeZone
|
||||
import kotlinx.datetime.toLocalDateTime
|
||||
import kotlin.time.Clock
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.Instant
|
||||
|
||||
enum class Severity {
|
||||
Debug,
|
||||
Verbose,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
None,
|
||||
}
|
||||
|
||||
enum class TreeRoots {
|
||||
Navigation,
|
||||
Koin,
|
||||
AssetsParser,
|
||||
DesignSystem,
|
||||
Settings,
|
||||
}
|
||||
|
||||
private data class LogEntry(
|
||||
val timestamp: Instant,
|
||||
val severity: Severity,
|
||||
val tag: String,
|
||||
val message: String,
|
||||
)
|
||||
|
||||
private interface LogTree {
|
||||
val maxEntries: Int
|
||||
val logs: ArrayDeque<LogEntry>
|
||||
|
||||
fun log(
|
||||
severity: Severity,
|
||||
tag: String,
|
||||
message: String,
|
||||
)
|
||||
|
||||
fun getFormattedLogs(): String
|
||||
}
|
||||
|
||||
private class MemoryLogTree(
|
||||
override val maxEntries: Int,
|
||||
) : LogTree {
|
||||
override val logs = ArrayDeque<LogEntry>(maxEntries)
|
||||
private val logsLock = SynchronizedObject()
|
||||
|
||||
override fun log(
|
||||
severity: Severity,
|
||||
tag: String,
|
||||
message: String,
|
||||
) {
|
||||
synchronized(logsLock) {
|
||||
if (logs.size >= maxEntries) {
|
||||
logs.removeFirst()
|
||||
}
|
||||
logs.addLast(LogEntry(Clock.System.now(), severity, tag, message))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFormattedLogs(): String =
|
||||
buildString {
|
||||
synchronized(logsLock) {
|
||||
logs.forEach { entry ->
|
||||
appendLine(
|
||||
"${entry.timestamp.toLocalDateTime(TimeZone.currentSystemDefault())} " +
|
||||
"${entry.severity.name.padEnd(7)} " +
|
||||
"${entry.tag}: ${entry.message}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal expect fun logPlatform(
|
||||
severity: Severity,
|
||||
tag: String,
|
||||
message: String,
|
||||
)
|
||||
|
||||
class Trace {
|
||||
companion object {
|
||||
private const val DEFAULT_LOG_MESSAGE = "The message content was empty"
|
||||
|
||||
private var _isDebug: Boolean = false
|
||||
private var _minSeverity: Severity = Severity.None
|
||||
private var _treeSize: Int = 20
|
||||
private val _trees = HashMap<String, LogTree>()
|
||||
|
||||
fun initialize(isDebug: Boolean) {
|
||||
_isDebug = isDebug
|
||||
_minSeverity = if (_isDebug) Severity.Verbose else Severity.None
|
||||
plantTree(TreeRoots.Navigation)
|
||||
plantTree(TreeRoots.Koin)
|
||||
plantTree(TreeRoots.AssetsParser)
|
||||
plantTree(TreeRoots.DesignSystem)
|
||||
plantTree(TreeRoots.Settings)
|
||||
}
|
||||
|
||||
fun setLoggingSeverity(severity: Severity) {
|
||||
_minSeverity = severity
|
||||
}
|
||||
|
||||
fun setTreeSizes(size: Int) {
|
||||
_treeSize = size
|
||||
}
|
||||
|
||||
private fun plantTree(name: TreeRoots) {
|
||||
_trees[name.name] = MemoryLogTree(_treeSize)
|
||||
}
|
||||
|
||||
fun plantTree(name: String) {
|
||||
_trees[name] = MemoryLogTree(_treeSize)
|
||||
}
|
||||
|
||||
fun getTreeContent(name: String): String = _trees[name]?.getFormattedLogs() ?: "Tree '$name' not found"
|
||||
|
||||
private fun log(
|
||||
severity: Severity,
|
||||
tag: String,
|
||||
message: String,
|
||||
) {
|
||||
if (severity == Severity.None || severity.ordinal < _minSeverity.ordinal) return
|
||||
logPlatform(severity, "Trace - $tag", message)
|
||||
_trees.values.forEach { tree ->
|
||||
tree.log(severity, tag, message)
|
||||
}
|
||||
}
|
||||
|
||||
fun v(
|
||||
tag: TreeRoots,
|
||||
message: String,
|
||||
) {
|
||||
v(tag.name, message)
|
||||
}
|
||||
|
||||
fun d(
|
||||
tag: TreeRoots,
|
||||
message: String,
|
||||
) {
|
||||
d(tag.name, message)
|
||||
}
|
||||
|
||||
fun i(
|
||||
tag: TreeRoots,
|
||||
message: String,
|
||||
) {
|
||||
i(tag.name, message)
|
||||
}
|
||||
|
||||
fun w(
|
||||
tag: TreeRoots,
|
||||
message: String,
|
||||
) {
|
||||
w(tag.name, message)
|
||||
}
|
||||
|
||||
fun e(
|
||||
tag: TreeRoots,
|
||||
message: String,
|
||||
) {
|
||||
e(tag.name, message)
|
||||
}
|
||||
|
||||
fun v(
|
||||
tag: String,
|
||||
message: String?,
|
||||
) {
|
||||
log(Severity.Verbose, tag, message ?: DEFAULT_LOG_MESSAGE)
|
||||
}
|
||||
|
||||
fun d(
|
||||
tag: String,
|
||||
message: String?,
|
||||
) {
|
||||
log(Severity.Debug, tag, message ?: DEFAULT_LOG_MESSAGE)
|
||||
}
|
||||
|
||||
fun i(
|
||||
tag: String,
|
||||
message: String?,
|
||||
) {
|
||||
log(Severity.Info, tag, message ?: DEFAULT_LOG_MESSAGE)
|
||||
}
|
||||
|
||||
fun w(
|
||||
tag: String,
|
||||
message: String?,
|
||||
) {
|
||||
log(Severity.Warn, tag, message ?: DEFAULT_LOG_MESSAGE)
|
||||
}
|
||||
|
||||
fun e(
|
||||
tag: String,
|
||||
message: String?,
|
||||
) {
|
||||
log(Severity.Error, tag, message ?: DEFAULT_LOG_MESSAGE)
|
||||
}
|
||||
|
||||
fun e(
|
||||
tag: String,
|
||||
message: String,
|
||||
throwable: Throwable,
|
||||
) {
|
||||
log(
|
||||
Severity.Error,
|
||||
tag,
|
||||
(message + "\n" + throwable.message + "\n" + throwable.stackTraceToString()),
|
||||
)
|
||||
}
|
||||
|
||||
fun e(
|
||||
tag: String,
|
||||
message: String,
|
||||
exception: Exception,
|
||||
) {
|
||||
log(
|
||||
Severity.Error,
|
||||
tag,
|
||||
(message + "\n" + exception.message + "\n" + exception.stackTraceToString()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cl.homelogic.platform.common.logging
|
||||
|
||||
import org.koin.core.logger.Level
|
||||
import org.koin.core.logger.Logger
|
||||
import org.koin.core.logger.MESSAGE
|
||||
|
||||
class TraceKoinLogger : Logger() {
|
||||
override fun display(
|
||||
level: Level,
|
||||
msg: MESSAGE,
|
||||
) {
|
||||
when (level) {
|
||||
Level.DEBUG -> Trace.d(DEFAULT_TAG, msg)
|
||||
Level.INFO -> Trace.i(DEFAULT_TAG, msg)
|
||||
Level.WARNING -> Trace.w(DEFAULT_TAG, msg)
|
||||
Level.ERROR -> Trace.e(DEFAULT_TAG, msg)
|
||||
Level.NONE -> {}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_TAG = "Koin"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package cl.homelogic.platform.common.permissions
|
||||
|
||||
import cl.homelogic.platform.common.permissions.PermissionStatus.Denied
|
||||
import cl.homelogic.platform.common.permissions.PermissionStatus.Granted
|
||||
import cl.homelogic.platform.common.permissions.PermissionStatus.NotGranted
|
||||
import dev.icerock.moko.permissions.Permission
|
||||
import dev.icerock.moko.permissions.PermissionState
|
||||
import dev.icerock.moko.permissions.bluetooth.BluetoothAdvertisePermission
|
||||
import dev.icerock.moko.permissions.bluetooth.BluetoothConnectPermission
|
||||
import dev.icerock.moko.permissions.bluetooth.BluetoothLEPermission
|
||||
import dev.icerock.moko.permissions.bluetooth.BluetoothScanPermission
|
||||
import dev.icerock.moko.permissions.camera.CameraPermission
|
||||
import dev.icerock.moko.permissions.contacts.ContactPermission
|
||||
import dev.icerock.moko.permissions.gallery.GalleryPermission
|
||||
import dev.icerock.moko.permissions.location.BackgroundLocationPermission
|
||||
import dev.icerock.moko.permissions.location.CoarseLocationPermission
|
||||
import dev.icerock.moko.permissions.location.LocationPermission
|
||||
import dev.icerock.moko.permissions.microphone.RecordAudioPermission
|
||||
import dev.icerock.moko.permissions.motion.MotionPermission
|
||||
import dev.icerock.moko.permissions.notifications.RemoteNotificationPermission
|
||||
import dev.icerock.moko.permissions.storage.StoragePermission
|
||||
import dev.icerock.moko.permissions.storage.WriteStoragePermission
|
||||
|
||||
enum class PermissionType {
|
||||
CAMERA,
|
||||
GALLERY,
|
||||
STORAGE,
|
||||
WRITE_STORAGE,
|
||||
LOCATION,
|
||||
COARSE_LOCATION,
|
||||
BACKGROUND_LOCATION,
|
||||
BLUETOOTH_LE,
|
||||
REMOTE_NOTIFICATION,
|
||||
RECORD_AUDIO,
|
||||
BLUETOOTH_SCAN,
|
||||
BLUETOOTH_ADVERTISE,
|
||||
BLUETOOTH_CONNECT,
|
||||
CONTACTS,
|
||||
MOTION,
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun PermissionType.toMokoPermission() =
|
||||
when (this) {
|
||||
CAMERA -> CameraPermission
|
||||
GALLERY -> GalleryPermission
|
||||
STORAGE -> StoragePermission
|
||||
WRITE_STORAGE -> WriteStoragePermission
|
||||
LOCATION -> LocationPermission
|
||||
COARSE_LOCATION -> CoarseLocationPermission
|
||||
BACKGROUND_LOCATION -> BackgroundLocationPermission
|
||||
BLUETOOTH_LE -> BluetoothLEPermission
|
||||
REMOTE_NOTIFICATION -> RemoteNotificationPermission
|
||||
RECORD_AUDIO -> RecordAudioPermission
|
||||
BLUETOOTH_SCAN -> BluetoothScanPermission
|
||||
BLUETOOTH_ADVERTISE -> BluetoothAdvertisePermission
|
||||
BLUETOOTH_CONNECT -> BluetoothConnectPermission
|
||||
CONTACTS -> ContactPermission
|
||||
MOTION -> MotionPermission
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PermissionState.toPermissionStatus() =
|
||||
when (this) {
|
||||
PermissionState.NotDetermined -> NotGranted
|
||||
PermissionState.NotGranted -> NotGranted
|
||||
PermissionState.Granted -> Granted
|
||||
PermissionState.Denied -> Denied
|
||||
PermissionState.DeniedAlways -> Denied
|
||||
}
|
||||
|
||||
enum class PermissionStatus {
|
||||
NotGranted,
|
||||
Granted,
|
||||
Denied,
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package cl.homelogic.platform.common.permissions.composables
|
||||
|
||||
import androidx.compose.foundation.layout.LayoutScopeMarker
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.remember
|
||||
import cl.homelogic.platform.common.permissions.PermissionStatus
|
||||
import cl.homelogic.platform.common.permissions.PermissionType
|
||||
import cl.homelogic.platform.common.permissions.PermissionType.Companion.toMokoPermission
|
||||
import cl.homelogic.platform.common.permissions.toPermissionStatus
|
||||
import dev.icerock.moko.permissions.DeniedAlwaysException
|
||||
import dev.icerock.moko.permissions.DeniedException
|
||||
import dev.icerock.moko.permissions.PermissionsController
|
||||
import dev.icerock.moko.permissions.RequestCanceledException
|
||||
import dev.icerock.moko.permissions.compose.PermissionsControllerFactory
|
||||
import dev.icerock.moko.permissions.compose.rememberPermissionsControllerFactory
|
||||
|
||||
@Composable
|
||||
fun PermissionSystem(
|
||||
content: @Composable PermissionsScope.() -> Unit,
|
||||
) {
|
||||
val factory: PermissionsControllerFactory = rememberPermissionsControllerFactory()
|
||||
val controller: PermissionsController = remember(factory) {
|
||||
factory.createPermissionsController()
|
||||
}
|
||||
|
||||
PermissionsScopeInstance(controller).content()
|
||||
}
|
||||
|
||||
@LayoutScopeMarker
|
||||
@Immutable
|
||||
interface PermissionsScope {
|
||||
suspend fun requestPermission(permission: PermissionType): PermissionStatus
|
||||
|
||||
suspend fun isPermissionGranted(permission: PermissionType): Boolean
|
||||
|
||||
suspend fun getPermissionState(permission: PermissionType): PermissionStatus
|
||||
|
||||
fun openAppSettings()
|
||||
}
|
||||
|
||||
internal class PermissionsScopeInstance(
|
||||
private val permissionsController: PermissionsController,
|
||||
) : PermissionsScope {
|
||||
override suspend fun requestPermission(permission: PermissionType): PermissionStatus {
|
||||
try {
|
||||
permissionsController.providePermission(permission.toMokoPermission())
|
||||
return PermissionStatus.Granted
|
||||
} catch (deniedAlways: DeniedAlwaysException) {
|
||||
return PermissionStatus.Denied
|
||||
} catch (denied: DeniedException) {
|
||||
return PermissionStatus.Denied
|
||||
} catch (canceled: RequestCanceledException) {
|
||||
return PermissionStatus.NotGranted
|
||||
} catch (exception: Exception) {
|
||||
return PermissionStatus.NotGranted
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun isPermissionGranted(permission: PermissionType): Boolean =
|
||||
permissionsController.isPermissionGranted(
|
||||
permission.toMokoPermission(),
|
||||
)
|
||||
|
||||
override suspend fun getPermissionState(permission: PermissionType): PermissionStatus =
|
||||
permissionsController
|
||||
.getPermissionState(
|
||||
permission.toMokoPermission(),
|
||||
).toPermissionStatus()
|
||||
|
||||
override fun openAppSettings() {
|
||||
permissionsController.openAppSettings()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package cl.homelogic.platform.common.settings
|
||||
|
||||
import cl.homelogic.platform.common.logging.Trace
|
||||
import cl.homelogic.platform.common.logging.TreeRoots
|
||||
import com.russhwolf.settings.Settings
|
||||
|
||||
interface ISettingsSource {
|
||||
fun <T> get(
|
||||
key: PreferenceKey<T>,
|
||||
defaultValue: T,
|
||||
): T
|
||||
|
||||
fun <T> set(
|
||||
key: PreferenceKey<T>,
|
||||
value: T,
|
||||
)
|
||||
|
||||
fun <T> remove(key: PreferenceKey<T>)
|
||||
|
||||
fun clear()
|
||||
}
|
||||
|
||||
class SettingsSource(
|
||||
private val settings: Settings,
|
||||
) : ISettingsSource {
|
||||
// TODO: add fuction to check if key exists
|
||||
|
||||
override fun <T> get(
|
||||
key: PreferenceKey<T>,
|
||||
defaultValue: T,
|
||||
): T {
|
||||
Trace.d(TreeRoots.Settings, "Retrieving setting: ${key.key}")
|
||||
return key.getValue(settings, defaultValue)
|
||||
}
|
||||
|
||||
override fun <T> set(
|
||||
key: PreferenceKey<T>,
|
||||
value: T,
|
||||
) {
|
||||
Trace.d(TreeRoots.Settings, "Storing setting: ${key.key} : $value")
|
||||
key.setValue(settings, value)
|
||||
}
|
||||
|
||||
override fun <T> remove(key: PreferenceKey<T>) {
|
||||
Trace.d(TreeRoots.Settings, "Removing setting: ${key.key}")
|
||||
settings.remove(key.key)
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
Trace.d(TreeRoots.Settings, "Deleting all settings")
|
||||
settings.clear()
|
||||
}
|
||||
}
|
||||
|
||||
interface ISettingsFactory {
|
||||
fun createSettings(name: String? = null): Settings
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package cl.homelogic.platform.common.settings
|
||||
|
||||
import com.russhwolf.settings.Settings
|
||||
|
||||
sealed class PreferenceKey<T>(
|
||||
val key: String,
|
||||
) {
|
||||
abstract fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: T,
|
||||
): T
|
||||
|
||||
abstract fun setValue(
|
||||
settings: Settings,
|
||||
value: T,
|
||||
)
|
||||
|
||||
class StringKey(
|
||||
key: String,
|
||||
) : PreferenceKey<String>(key) {
|
||||
override fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: String,
|
||||
): String = settings.getString(key, defaultValue)
|
||||
|
||||
override fun setValue(
|
||||
settings: Settings,
|
||||
value: String,
|
||||
) = settings.putString(key, value)
|
||||
}
|
||||
|
||||
class IntKey(
|
||||
key: String,
|
||||
) : PreferenceKey<Int>(key) {
|
||||
override fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: Int,
|
||||
): Int = settings.getInt(key, defaultValue)
|
||||
|
||||
override fun setValue(
|
||||
settings: Settings,
|
||||
value: Int,
|
||||
) = settings.putInt(key, value)
|
||||
}
|
||||
|
||||
class LongKey(
|
||||
key: String,
|
||||
) : PreferenceKey<Long>(key) {
|
||||
override fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: Long,
|
||||
): Long = settings.getLong(key, defaultValue)
|
||||
|
||||
override fun setValue(
|
||||
settings: Settings,
|
||||
value: Long,
|
||||
) = settings.putLong(key, value)
|
||||
}
|
||||
|
||||
class FloatKey(
|
||||
key: String,
|
||||
) : PreferenceKey<Float>(key) {
|
||||
override fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: Float,
|
||||
): Float = settings.getFloat(key, defaultValue)
|
||||
|
||||
override fun setValue(
|
||||
settings: Settings,
|
||||
value: Float,
|
||||
) = settings.putFloat(key, value)
|
||||
}
|
||||
|
||||
class DoubleKey(
|
||||
key: String,
|
||||
) : PreferenceKey<Double>(key) {
|
||||
override fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: Double,
|
||||
): Double = settings.getDouble(key, defaultValue)
|
||||
|
||||
override fun setValue(
|
||||
settings: Settings,
|
||||
value: Double,
|
||||
) = settings.putDouble(key, value)
|
||||
}
|
||||
|
||||
class BooleanKey(
|
||||
key: String,
|
||||
) : PreferenceKey<Boolean>(key) {
|
||||
override fun getValue(
|
||||
settings: Settings,
|
||||
defaultValue: Boolean,
|
||||
): Boolean = settings.getBoolean(key, defaultValue)
|
||||
|
||||
override fun setValue(
|
||||
settings: Settings,
|
||||
value: Boolean,
|
||||
) = settings.putBoolean(key, value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package cl.homelogic.platform.common
|
||||
|
||||
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
|
||||
actual object Platform {
|
||||
actual fun getType() = PlatformTypes.IOS
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cl.homelogic.platform.common.logging
|
||||
|
||||
import platform.Foundation.NSLog
|
||||
|
||||
internal actual fun logPlatform(
|
||||
severity: Severity,
|
||||
tag: String,
|
||||
message: String,
|
||||
) {
|
||||
if (severity == Severity.None) return
|
||||
NSLog("Trace - $tag [${severity.name}]: $message")
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cl.homelogic.platform.common.settings
|
||||
|
||||
import com.russhwolf.settings.NSUserDefaultsSettings
|
||||
import com.russhwolf.settings.Settings
|
||||
import platform.Foundation.NSUserDefaults
|
||||
|
||||
class IOSSettingsFactory : ISettingsFactory {
|
||||
override fun createSettings(name: String?): Settings {
|
||||
val userDefaults = if (name != null) {
|
||||
NSUserDefaults(suiteName = name)
|
||||
} else {
|
||||
NSUserDefaults.standardUserDefaults
|
||||
}
|
||||
return NSUserDefaultsSettings(userDefaults)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user