Improve settings interface, move iOS project

This commit is contained in:
2025-12-21 13:47:17 +03:00
Unverified
parent b18af36b3e
commit 0c7697aef8
23 changed files with 95 additions and 215 deletions
+4 -1
View File
@@ -18,6 +18,9 @@ build
.cxx .cxx
local.properties local.properties
keys app/android/keys
releases releases
release release
*.xcuserstate
xcuserdata
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="XcodeMetaData" PROJECT_DIR="$PROJECT_DIR$/iosApp" PROJECT_FILE="$PROJECT_DIR$/iosApp/iosApp.xcodeproj" /> <component name="XcodeMetaData" PROJECT_DIR="$PROJECT_DIR$/iosApp" PROJECT_FILE="$PROJECT_DIR$/app/ios/iosApp.xcodeproj" />
</project> </project>
+5 -3
View File
@@ -1,4 +1,5 @@
import com.android.build.gradle.tasks.MergeSourceSetFolders
import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.io.FileInputStream import java.io.FileInputStream
import java.util.Properties import java.util.Properties
@@ -50,9 +51,10 @@ android {
signingConfigs { signingConfigs {
create("release") { create("release") {
val keystoreProperties = Properties().apply { val keystoreProperties = Properties().apply {
load(FileInputStream(rootProject.file("keys/keystore.properties"))) load(FileInputStream(file("keys/keystore.properties")))
} }
storeFile = rootProject.file("keys/release.jks")
storeFile = file("keys/release.jks")
keyAlias = "release" keyAlias = "release"
storePassword = keystoreProperties["storePassword"].toString() storePassword = keystoreProperties["storePassword"].toString()
keyPassword = keystoreProperties["keyPassword"].toString() keyPassword = keystoreProperties["keyPassword"].toString()
@@ -91,7 +93,7 @@ android {
} }
} }
tasks.withType<com.android.build.gradle.tasks.MergeSourceSetFolders>().configureEach { tasks.withType<MergeSourceSetFolders>().configureEach {
dependsOn(fixComposeResourcesStructure) dependsOn(fixComposeResourcesStructure)
} }
@@ -161,6 +161,7 @@
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = { F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
@@ -175,7 +176,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n"; shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/../../\"\n./gradlew :app:shared:embedAndSignAppleFrameworkForXcode\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@@ -327,7 +328,7 @@
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
); );
INFOPLIST_FILE = iosApp/Info.plist; INFOPLIST_FILE = iosApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = FromChat; INFOPLIST_KEY_CFBundleDisplayName = FromChat;
@@ -359,7 +360,7 @@
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
); );
INFOPLIST_FILE = iosApp/Info.plist; INFOPLIST_FILE = iosApp/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = FromChat; INFOPLIST_KEY_CFBundleDisplayName = FromChat;

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 184 KiB

@@ -1,17 +1,26 @@
package ru.fromchat.core package ru.fromchat.core
import ru.fromchat.ui.Theme
import com.pr0gramm3r101.utils.settings.Settings import com.pr0gramm3r101.utils.settings.Settings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import ru.fromchat.ui.Theme
object Settings { object Settings {
private val settings = Settings.Companion() private val settings = Settings()
private fun runIO(block: suspend CoroutineScope.() -> Unit) {
CoroutineScope(Dispatchers.IO).launch(block = block)
}
var materialYou: Boolean var materialYou: Boolean
get() = settings.getBoolean("materialYou", true) get() = runBlocking { settings.getBoolean("materialYou", true) }
set(value) = settings.putBoolean("materialYou", value) set(value) = runIO { settings.putBoolean("materialYou", value) }
var theme: Theme var theme: Theme
get() = Theme.entries[settings.getInt("theme", Theme.AsSystem.ordinal)] get() = runBlocking { Theme.entries[settings.getInt("theme", Theme.AsSystem.ordinal)] }
set(value) = settings.putInt("theme", value.ordinal) set(value) = runIO { settings.putInt("theme", value.ordinal) }
} }
@@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
BuildableName = "FromChat.app"
BlueprintName = "iosApp"
ReferencedContainer = "container:iosApp.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7555FF7A242A565900829871"
BuildableName = "FromChat.app"
BlueprintName = "iosApp"
ReferencedContainer = "container:iosApp.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<LocationScenarioReference
identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
referenceType = "1">
</LocationScenarioReference>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>iOS.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>7555FF7A242A565900829871</key>
<dict>
<key>primary</key>
<true />
</dict>
</dict>
</dict>
</plist>
@@ -1,7 +1,5 @@
package com.pr0gramm3r101.utils.settings package com.pr0gramm3r101.utils.settings
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.floatPreferencesKey import androidx.datastore.preferences.core.floatPreferencesKey
@@ -11,96 +9,81 @@ import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
class AndroidSettings(): Settings { class AndroidSettings(): Settings {
private val dataStore: DataStore<Preferences> private val dataStore get() = DataStoreSingleton.dataStore
get() = DataStoreSingleton.dataStore
override fun putString(key: String, value: String) { override suspend fun putString(key: String, value: String) {
runBlocking {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[stringPreferencesKey(key)] = value preferences[stringPreferencesKey(key)] = value
} }
} }
}
override fun getString(key: String, default: String) = runBlocking { override suspend fun getString(key: String, default: String) =
dataStore.data.map { preferences -> dataStore.data.map { preferences ->
preferences[stringPreferencesKey(key)] ?: default preferences[stringPreferencesKey(key)] ?: default
}.first() }.first()
}
override fun putInt(key: String, value: Int) = runBlocking { override suspend fun putInt(key: String, value: Int) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[intPreferencesKey(key)] = value preferences[intPreferencesKey(key)] = value
} }
Unit
} }
override fun getInt(key: String, default: Int) = runBlocking { override suspend fun getInt(key: String, default: Int) =
dataStore.data.map { preferences -> dataStore.data.map { preferences ->
preferences[intPreferencesKey(key)] ?: default preferences[intPreferencesKey(key)] ?: default
}.first() }.first()
}
override fun putLong(key: String, value: Long) = runBlocking { override suspend fun putLong(key: String, value: Long) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[longPreferencesKey(key)] = value preferences[longPreferencesKey(key)] = value
} }
Unit
} }
override fun getLong(key: String, default: Long) = runBlocking { override suspend fun getLong(key: String, default: Long) =
dataStore.data.map { preferences -> dataStore.data.map { preferences ->
preferences[longPreferencesKey(key)] ?: default preferences[longPreferencesKey(key)] ?: default
}.first() }.first()
}
override fun putFloat(key: String, value: Float) = runBlocking { override suspend fun putFloat(key: String, value: Float) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[floatPreferencesKey(key)] = value preferences[floatPreferencesKey(key)] = value
} }
Unit
} }
override fun getFloat(key: String, default: Float) = runBlocking { override suspend fun getFloat(key: String, default: Float) =
dataStore.data.map { preferences -> dataStore.data.map { preferences ->
preferences[floatPreferencesKey(key)] ?: default preferences[floatPreferencesKey(key)] ?: default
}.first() }.first()
}
override fun putBoolean(key: String, value: Boolean) = runBlocking { override suspend fun putBoolean(key: String, value: Boolean) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[booleanPreferencesKey(key)] = value preferences[booleanPreferencesKey(key)] = value
} }
Unit
} }
override fun getBoolean(key: String, default: Boolean) = runBlocking { override suspend fun getBoolean(key: String, default: Boolean) =
dataStore.data.map { preferences -> dataStore.data.map { preferences ->
preferences[booleanPreferencesKey(key)] ?: default preferences[booleanPreferencesKey(key)] ?: default
}.first() }.first()
}
override fun putStringSet(key: String, value: Set<String>) = runBlocking { override suspend fun putStringSet(key: String, value: Set<String>) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences[stringSetPreferencesKey(key)] = value preferences[stringSetPreferencesKey(key)] = value
} }
Unit
} }
override fun getStringSet(key: String, default: Set<String>) = runBlocking { override suspend fun getStringSet(key: String, default: Set<String>) =
dataStore.data.map { preferences -> dataStore.data.map { preferences ->
preferences[stringSetPreferencesKey(key)] ?: default preferences[stringSetPreferencesKey(key)] ?: default
}.first() }.first()
}
override fun putStringList(key: String, value: List<String>) = putStringSet(key, value.toSet()) override suspend fun putStringList(key: String, value: List<String>) = putStringSet(key, value.toSet())
override fun getStringList(key: String, default: List<String>) = getStringSet(key, default.toSet()).toList() override suspend fun getStringList(key: String, default: List<String>) = getStringSet(key, default.toSet()).toList()
override fun remove(key: String) = runBlocking { override suspend fun remove(key: String) {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences.remove(stringPreferencesKey(key)) preferences.remove(stringPreferencesKey(key))
preferences.remove(intPreferencesKey(key)) preferences.remove(intPreferencesKey(key))
@@ -109,6 +92,5 @@ class AndroidSettings(): Settings {
preferences.remove(booleanPreferencesKey(key)) preferences.remove(booleanPreferencesKey(key))
preferences.remove(stringSetPreferencesKey(key)) preferences.remove(stringSetPreferencesKey(key))
} }
Unit
} }
} }
@@ -8,26 +8,26 @@ interface Settings {
inline operator fun invoke() = settings inline operator fun invoke() = settings
} }
fun putString(key: String, value: String) suspend fun putString(key: String, value: String)
fun getString(key: String, default: String = ""): String suspend fun getString(key: String, default: String = ""): String
fun putInt(key: String, value: Int) suspend fun putInt(key: String, value: Int)
fun getInt(key: String, default: Int = 0): Int suspend fun getInt(key: String, default: Int = 0): Int
fun putLong(key: String, value: Long) suspend fun putLong(key: String, value: Long)
fun getLong(key: String, default: Long = 0L): Long suspend fun getLong(key: String, default: Long = 0L): Long
fun putFloat(key: String, value: Float) suspend fun putFloat(key: String, value: Float)
fun getFloat(key: String, default: Float = 0f): Float suspend fun getFloat(key: String, default: Float = 0f): Float
fun putBoolean(key: String, value: Boolean) suspend fun putBoolean(key: String, value: Boolean)
fun getBoolean(key: String, default: Boolean = false): Boolean suspend fun getBoolean(key: String, default: Boolean = false): Boolean
fun putStringSet(key: String, value: Set<String>) suspend fun putStringSet(key: String, value: Set<String>)
fun getStringSet(key: String, default: Set<String> = emptySet()): Set<String> suspend fun getStringSet(key: String, default: Set<String> = emptySet()): Set<String>
fun putStringList(key: String, value: List<String>) suspend fun putStringList(key: String, value: List<String>)
fun getStringList(key: String, default: List<String> = emptyList()): List<String> suspend fun getStringList(key: String, default: List<String> = emptyList()): List<String>
fun remove(key: String) suspend fun remove(key: String)
} }
@@ -6,65 +6,40 @@ import platform.Foundation.NSUserDefaults
class IosSettings : Settings { class IosSettings : Settings {
private val defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults private val defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults
override fun putString(key: String, value: String) { override suspend fun putString(key: String, value: String) = defaults.setObject(value, key)
defaults.setObject(value, key)
override suspend fun getString(key: String, default: String) = defaults.stringForKey(key) ?: default
override suspend fun putInt(key: String, value: Int) = defaults.setInteger(value.toLong(), key)
override suspend fun getInt(key: String, default: Int) = defaults.integerForKey(key).toInt()
override suspend fun putLong(key: String, value: Long) = defaults.setObject(value, key)
override suspend fun getLong(key: String, default: Long) = defaults.objectForKey(key) as? Long ?: default
override suspend fun putFloat(key: String, value: Float) = defaults.setFloat(value, key)
override suspend fun getFloat(key: String, default: Float) = defaults.floatForKey(key)
override suspend fun putBoolean(key: String, value: Boolean) = defaults.setBool(value, key)
override suspend fun getBoolean(key: String, default: Boolean) = defaults.boolForKey(key)
override suspend fun putStringSet(key: String, value: Set<String>) = defaults.setObject(value.toList(), key)
override suspend fun getStringSet(key: String, default: Set<String>): Set<String> {
return (defaults.objectForKey(key) as? List<*> ?: return default)
.filterIsInstance<String>()
.toSet()
} }
override fun getString(key: String, default: String): String { override suspend fun putStringList(key: String, value: List<String>) = defaults.setObject(value, key)
return defaults.stringForKey(key) ?: default
override suspend fun getStringList(key: String, default: List<String>): List<String> {
return (defaults.objectForKey(key) as? List<*> ?: return default)
.filterIsInstance<String>()
} }
override fun putInt(key: String, value: Int) { override suspend fun remove(key: String) = defaults.removeObjectForKey(key)
defaults.setInteger(value.toLong(), key)
}
override fun getInt(key: String, default: Int): Int {
return defaults.integerForKey(key).toInt()
}
override fun putLong(key: String, value: Long) {
defaults.setObject(value, key)
}
override fun getLong(key: String, default: Long): Long {
return defaults.objectForKey(key) as? Long ?: default
}
override fun putFloat(key: String, value: Float) {
defaults.setFloat(value, key)
}
override fun getFloat(key: String, default: Float): Float {
return defaults.floatForKey(key)
}
override fun putBoolean(key: String, value: Boolean) {
defaults.setBool(value, key)
}
override fun getBoolean(key: String, default: Boolean): Boolean {
return defaults.boolForKey(key)
}
override fun putStringSet(key: String, value: Set<String>) {
defaults.setObject(value.toList(), key)
}
override fun getStringSet(key: String, default: Set<String>): Set<String> {
val list = defaults.objectForKey(key) as? List<*> ?: return default
return list.filterIsInstance<String>().toSet()
}
override fun putStringList(key: String, value: List<String>) {
defaults.setObject(value, key)
}
override fun getStringList(key: String, default: List<String>): List<String> {
val list = defaults.objectForKey(key) as? List<*> ?: return default
return list.filterIsInstance<String>()
}
override fun remove(key: String) {
defaults.removeObjectForKey(key)
}
} }