diff --git a/.idea/.gitignore b/.idea/.gitignore
index 13566b8..a9d7db9 100644
--- a/.idea/.gitignore
+++ b/.idea/.gitignore
@@ -6,3 +6,5 @@
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+# GitHub Copilot persisted chat sessions
+/copilot/chatSessions
diff --git a/.idea/.name b/.idea/.name
index 40fc7f7..5951875 100644
--- a/.idea/.name
+++ b/.idea/.name
@@ -1 +1 @@
-Genesis
\ No newline at end of file
+uninit-genesis
\ No newline at end of file
diff --git a/.idea/artifacts/appDesktop_jvm_0_0_1_1705247358741_ginseng.xml b/.idea/artifacts/appDesktop_jvm_0_0_1_1705247358741_ginseng.xml
new file mode 100644
index 0000000..ee13aec
--- /dev/null
+++ b/.idea/artifacts/appDesktop_jvm_0_0_1_1705247358741_ginseng.xml
@@ -0,0 +1,6 @@
+
+
+ $PROJECT_DIR$/appDesktop/build/libs
+
+
+
\ No newline at end of file
diff --git a/.idea/artifacts/app_desktop_0_0_1_1705247358741_ginseng.xml b/.idea/artifacts/app_desktop_0_0_1_1705247358741_ginseng.xml
new file mode 100644
index 0000000..7833add
--- /dev/null
+++ b/.idea/artifacts/app_desktop_0_0_1_1705247358741_ginseng.xml
@@ -0,0 +1,6 @@
+
+
+ $PROJECT_DIR$/genesis/app/build/libs
+
+
+
\ No newline at end of file
diff --git a/.idea/artifacts/client_desktop_0_0_1.xml b/.idea/artifacts/client_desktop_0_0_1.xml
index c507e6f..713b2b3 100644
--- a/.idea/artifacts/client_desktop_0_0_1.xml
+++ b/.idea/artifacts/client_desktop_0_0_1.xml
@@ -2,7 +2,7 @@
$PROJECT_DIR$/genesis/discord/client/build/libs
-
+
\ No newline at end of file
diff --git a/.idea/artifacts/genesisApi_desktop_0_0_1.xml b/.idea/artifacts/genesisApi_desktop_0_0_1.xml
index 88a2252..58d402d 100644
--- a/.idea/artifacts/genesisApi_desktop_0_0_1.xml
+++ b/.idea/artifacts/genesisApi_desktop_0_0_1.xml
@@ -2,7 +2,7 @@
$PROJECT_DIR$/genesis/genesisApi/build/libs
-
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 678b734..3dea034 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -4,8 +4,6 @@
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 05754f2..3d64f3c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,6 @@
{
- "java.project.sourcePaths": [""]
+ "java.project.sourcePaths": [""],
+ "java.project.referencedLibraries": [
+ "/home/aenri/.gradle/caches/**/*.jar"
+ ]
}
diff --git a/appAndroid/build.gradle.kts b/appAndroid/build.gradle.kts
index 2c4895a..19083c5 100644
--- a/appAndroid/build.gradle.kts
+++ b/appAndroid/build.gradle.kts
@@ -1,7 +1,8 @@
plugins {
kotlin("multiplatform")
id("com.android.application")
- id("org.jetbrains.compose")
+ alias(libs.plugins.kotlin.compose.compiler)
+// alias(libs.plugins.kotlin.compose.plugin)
}
kotlin {
diff --git a/appDesktop/build.gradle.kts b/appDesktop/build.gradle.kts
index 2849f12..03f8c8f 100644
--- a/appDesktop/build.gradle.kts
+++ b/appDesktop/build.gradle.kts
@@ -2,7 +2,8 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform")
- id("org.jetbrains.compose")
+ alias(libs.plugins.kotlin.compose.compiler)
+ alias(libs.plugins.kotlin.compose.plugin)
}
kotlin {
@@ -11,7 +12,14 @@ kotlin {
sourceSets {
val jvmMain by getting {
dependencies {
- implementation(compose.desktop.currentOs)
+ implementation(when (getCurrentTarget()) {
+ "windows-x64" -> libs.compose.desktop.jvm.windows.x64
+ "macos-x64" -> libs.compose.desktop.jvm.macos.x64
+ "linux-x64" -> libs.compose.desktop.jvm.linux.x64
+ "linux-arm64" -> libs.compose.desktop.jvm.linux.arm64
+ "macos-arm64" -> libs.compose.desktop.jvm.macos.arm64
+ else -> throw Exception("Unsupported target")
+ })
implementation(project(":genesis:app"))
}
}
@@ -46,3 +54,20 @@ compose.desktop {
}
}
}
+
+fun getCurrentTarget(): String {
+ val osSys = System.getProperty("os.name")
+ val OS = when {
+ osSys.contains("win", ignoreCase = true) -> "windows"
+ osSys.contains("mac", ignoreCase = true) -> "macos"
+ osSys.contains("nix") || osSys.contains("nux") || osSys.contains("aix") -> "linux"
+ else -> throw Exception("Unsupported OS")
+ }
+ val archSys = System.getProperty("os.arch")
+ val arch = when (archSys) {
+ "x86_64", "amd64" -> "x64"
+ "aarch64" -> "arm64"
+ else -> throw Exception("Unsupported arch")
+ }
+ return "$OS-$arch"
+}
diff --git a/appDesktop/src/jvmMain/kotlin/xyz/genesisapp/genesis/Application.kt b/appDesktop/src/jvmMain/kotlin/xyz/genesisapp/genesis/Application.kt
index 39b1410..9384cd2 100644
--- a/appDesktop/src/jvmMain/kotlin/xyz/genesisapp/genesis/Application.kt
+++ b/appDesktop/src/jvmMain/kotlin/xyz/genesisapp/genesis/Application.kt
@@ -2,10 +2,13 @@ package uninit.genesis
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.window.ApplicationScope
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import uninit.genesis.app.MainView
+import uninit.genesis.app.state.LocalContextMutableWindowTitle
class Application {
@@ -21,7 +24,14 @@ class Application {
@Composable
@Preview
fun ApplicationScope.content() {
- Window(onCloseRequest = ::exitApplication) {
- MainView()
+ CompositionLocalProvider(
+ LocalContextMutableWindowTitle provides mutableStateOf("Genesis"),
+ ) {
+ Window(
+ onCloseRequest = ::exitApplication,
+ title = LocalContextMutableWindowTitle.current.component1(),
+ ) {
+ MainView()
+ }
}
}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 5ae9b31..b14c3a0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -7,7 +7,8 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.multiplatform) apply false
- alias(libs.plugins.kotlin.compose) apply false
+ alias(libs.plugins.kotlin.compose.compiler) apply false
+// alias(libs.plugins.kotlin.compose.plugin) apply false
alias(libs.plugins.kotlinx.serialization) apply false
}
diff --git a/genesis/app/build.gradle.kts b/genesis/app/build.gradle.kts
index aca3f52..09fa425 100644
--- a/genesis/app/build.gradle.kts
+++ b/genesis/app/build.gradle.kts
@@ -1,7 +1,8 @@
plugins {
kotlin("multiplatform")
id("com.android.library")
- id("org.jetbrains.compose")
+ alias(libs.plugins.kotlin.compose.compiler)
+// alias(libs.plugins.kotlin.compose.plugin)
// id("dev.icerock.mobile.multiplatform-resources")
alias(libs.plugins.kotlinx.serialization)
}
@@ -21,15 +22,14 @@ kotlin {
sourceSets {
val commonMain by getting {
dependencies {
- implementation(compose.runtime)
- implementation(compose.foundation)
- implementation(compose.material3)
- implementation(compose.material)
- @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
- implementation(compose.components.resources)
+ implementation(libs.compose.runtime)
+ implementation(libs.compose.foundation)
+ implementation(libs.compose.material3)
+ implementation(libs.compose.material)
+ implementation(libs.compose.components.resources)
- api(libs.moko.resources.common)
- api(libs.moko.resources.compose)
+// api(libs.moko.resources.common)
+// api(libs.moko.resources.compose)
implementation(libs.serialization.json)
@@ -49,11 +49,11 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
- implementation(libs.kamel)
+// implementation(libs.kamel)
- implementation(libs.uninit.common)
- implementation(libs.uninit.common.compose)
+ implementation(project(":uninit:common"))
+ implementation(project(":uninit:common-compose"))
implementation(project(":genesis:discord:api"))
implementation(project(":genesis:discord:client"))
implementation(project(":genesis:genesisApi"))
@@ -67,12 +67,16 @@ kotlin {
api("androidx.appcompat:appcompat:1.6.1")
api("androidx.core:core-ktx:1.12.0")
implementation(libs.ktor.client.okhttp)
+
+ dependsOn(commonMain)
}
}
val desktopMain by getting {
dependencies {
- implementation(compose.desktop.common)
+ implementation(libs.compose.desktop.common)
implementation(libs.ktor.client.okhttp)
+
+ dependsOn(commonMain)
}
}
}
diff --git a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.android.kt b/genesis/app/src/androidMain/kotlin/uninit/genesis/app/KoinModules.android.kt
similarity index 57%
rename from genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.android.kt
rename to genesis/app/src/androidMain/kotlin/uninit/genesis/app/KoinModules.android.kt
index 5e1fd23..1173146 100644
--- a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.android.kt
+++ b/genesis/app/src/androidMain/kotlin/uninit/genesis/app/KoinModules.android.kt
@@ -1,4 +1,4 @@
-package uninit.genesis.app.di
+package uninit.genesis.app
import androidx.compose.runtime.Composable
import org.koin.core.module.Module
@@ -7,14 +7,15 @@ import uninit.common.compose.preferences.PreferencesManager
import uninit.genesis.app.platform.android.LocalApplicationContext
@Composable
-actual fun preferencesModule(): Module {
+actual fun platformNativeModuleImpl(): Module {
val context = LocalApplicationContext.current
return module {
- single {
+ single {
context?.let {
- return@single PreferencesManager(it.getSharedPreferences("genesis", 0))
+ return@single PreferenceManager(it.getSharedPreferences("genesis", Context.MODE_PRIVATE))
}
- throw IllegalStateException("Application context is not initialized")
+ throw IllegalStateException("Application Context is not initialized.")
}
}
+
}
\ No newline at end of file
diff --git a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/main.android.kt b/genesis/app/src/androidMain/kotlin/uninit/genesis/app/main.android.kt
similarity index 100%
rename from genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/main.android.kt
rename to genesis/app/src/androidMain/kotlin/uninit/genesis/app/main.android.kt
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/data/.gitkeep b/genesis/app/src/androidMain/kotlin/uninit/genesis/platform/android/LocalApplicationContext.kt
similarity index 100%
rename from genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/data/.gitkeep
rename to genesis/app/src/androidMain/kotlin/uninit/genesis/platform/android/LocalApplicationContext.kt
diff --git a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.android.kt b/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.android.kt
deleted file mode 100644
index 2c0a12c..0000000
--- a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.android.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package uninit.genesis.app.di
-
-import io.ktor.client.engine.*
-import io.ktor.client.engine.okhttp.*
-
-actual val platformHttpEngineFactory: HttpClientEngineFactory<*> = OkHttp
\ No newline at end of file
diff --git a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/platform/android/LocalApplicationContext.kt b/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/platform/android/LocalApplicationContext.kt
deleted file mode 100644
index 1c4a684..0000000
--- a/genesis/app/src/androidMain/kotlin/xyz/genesisapp/genesis/app/platform/android/LocalApplicationContext.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package uninit.genesis.app.platform.android
-
-import androidx.compose.runtime.compositionLocalOf
-
-@Suppress("USELESS_CAST")
-val LocalApplicationContext = compositionLocalOf { null as android.content.Context? }
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/App.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/App.kt
new file mode 100644
index 0000000..c9a2a32
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/App.kt
@@ -0,0 +1,32 @@
+package uninit.genesis.app
+
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.compositionLocalOf
+import cafe.adriel.voyager.navigator.Navigator
+import io.github.aakira.napier.Antilog
+import io.github.aakira.napier.Napier
+import org.koin.core.context.startKoin
+import org.koin.dsl.koinApplication
+import uninit.genesis.app.ui.screens.LaunchScreen
+import uninit.genesis.app.ui.theme.Theme
+import uninit.genesis.app.ui.theme.catppuccin.mocha.CTPMochaPink
+
+val LocalCompositionTheme = compositionLocalOf { CTPMochaPink }
+@Composable
+fun App() {
+ Napier.base(getAntiLog())
+ Napier.d("App started on ${getPlatformName()}")
+ val nativeModule = KoinModules.platformNativeModule()
+ startKoin {
+ modules(nativeModule)
+ }
+ CompositionLocalProvider( LocalCompositionTheme provides CTPMochaPink ) {
+ Navigator(LaunchScreen())
+ }
+}
+
+expect fun getPlatformName(): String
+
+expect fun getAntiLog(): Antilog
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/KoinModules.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/KoinModules.kt
new file mode 100644
index 0000000..bd212d0
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/KoinModules.kt
@@ -0,0 +1,20 @@
+package uninit.genesis.app
+
+import androidx.compose.runtime.Composable
+
+object KoinModules {
+ @Composable
+ fun platformNativeModule() = platformNativeModuleImpl()
+}
+
+/** PlatformNativeModule is a koin module that provides the following
+platform-specific dependencies:
+
+- preferencesManager: `PreferencesManager`
+- platformHttpEngineFactory: `HttpClientEngineFactory<*>`
+
+The implementation of this is required to be composable due to the
+nature of retrieving the preferencesManager for the Android platform.
+*/
+@Composable
+expect fun platformNativeModuleImpl(): org.koin.core.module.Module
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/state/LocalContextMutableWindowTitle.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/state/LocalContextMutableWindowTitle.kt
new file mode 100644
index 0000000..5b0557e
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/state/LocalContextMutableWindowTitle.kt
@@ -0,0 +1,6 @@
+package uninit.genesis.app.state
+
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.staticCompositionLocalOf
+
+val LocalContextMutableWindowTitle = staticCompositionLocalOf { mutableStateOf("Genesis") }
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/screens/LaunchScreen.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/screens/LaunchScreen.kt
new file mode 100644
index 0000000..fec2f85
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/screens/LaunchScreen.kt
@@ -0,0 +1,23 @@
+package uninit.genesis.app.ui.screens
+
+import androidx.compose.runtime.Composable
+import cafe.adriel.voyager.core.screen.Screen
+import cafe.adriel.voyager.navigator.LocalNavigator
+import cafe.adriel.voyager.navigator.currentOrThrow
+import org.koin.compose.getKoin
+import uninit.common.compose.preferences.PreferencesManager
+import uninit.genesis.app.ui.screens.onboarding.OnboardingScreen
+
+class LaunchScreen : Screen {
+
+ @Composable
+ override fun Content() {
+ val firstLaunch by getKoin().get().preference("completedOnboarding", false)
+
+ if (!firstLaunch) {
+ LocalNavigator.currentOrThrow.push(OnboardingScreen())
+ } else {
+ // Navigate to main screen
+ }
+ }
+}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/screens/onboarding/OnboardingScreen.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/screens/onboarding/OnboardingScreen.kt
new file mode 100644
index 0000000..3b3f543
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/screens/onboarding/OnboardingScreen.kt
@@ -0,0 +1,26 @@
+package uninit.genesis.app.ui.screens.onboarding
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import cafe.adriel.voyager.core.screen.Screen
+import uninit.genesis.app.LocalCompositionTheme
+
+class OnboardingScreen : Screen {
+ @Composable
+ override fun Content() {
+ val theme = LocalCompositionTheme.current
+// val windowSize = currentWindowAdaptiveInfo().windowSizeClass
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(theme.base)
+ ) {
+ Text(modifier = Modifier.align(Alignment.Center), text = "Onboarding", color = theme.text)
+ }
+ }
+}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/Theme.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/Theme.kt
new file mode 100644
index 0000000..cc15dab
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/Theme.kt
@@ -0,0 +1,10 @@
+package uninit.genesis.app.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+data class Theme(
+ val base: Color,
+ val overBase: Color,
+ val primary: Color,
+ val text: Color,
+)
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/catppuccin/mocha/CTPMochaPink.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/catppuccin/mocha/CTPMochaPink.kt
new file mode 100644
index 0000000..98e7629
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/catppuccin/mocha/CTPMochaPink.kt
@@ -0,0 +1,11 @@
+package uninit.genesis.app.ui.theme.catppuccin.mocha
+
+import uninit.genesis.app.ui.theme.Theme
+import uninit.genesis.app.ui.theme.rgb
+
+val CTPMochaPink = Theme(
+ base = rgb(17, 17, 27),
+ overBase = rgb(24, 24, 37),
+ primary = rgb(245, 194, 231),
+ text = rgb(205, 214, 244)
+)
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/rgb.kt b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/rgb.kt
new file mode 100644
index 0000000..eb097de
--- /dev/null
+++ b/genesis/app/src/commonMain/kotlin/uninit/genesis/app/ui/theme/rgb.kt
@@ -0,0 +1,9 @@
+package uninit.genesis.app.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+fun rgb(r: Int, g: Int, b: Int) = Color(
+ r / 255f,
+ g / 255f,
+ b / 255f,
+)
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/App.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/App.kt
deleted file mode 100644
index d517259..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/App.kt
+++ /dev/null
@@ -1,99 +0,0 @@
-package uninit.genesis.app
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.layout.Layout
-import cafe.adriel.voyager.navigator.Navigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import io.github.aakira.napier.Antilog
-import io.github.aakira.napier.Napier
-import org.koin.compose.KoinApplication
-import org.koin.compose.getKoin
-import uninit.common.compose.koin.uninitModule
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.client.enum.LogLevel
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.di.dataStoreModule
-import uninit.genesis.app.di.genesisApiModule
-import uninit.genesis.app.di.genesisClientModule
-import uninit.genesis.app.di.httpModule
-import uninit.genesis.app.di.platformHttpEngineFactory
-import uninit.genesis.app.di.preferencesModule
-import uninit.genesis.app.theme.LocalContextColors
-import uninit.genesis.app.theme.ThemeProvider
-import uninit.genesis.app.ui.screens.RootScreen
-
-@Composable
-fun App() {
- Napier.base(getAntiLog())
- val preferencesModule = preferencesModule()
- KoinApplication(application = {
- modules(
- preferencesModule,
- httpModule(),
- genesisClientModule(),
- genesisApiModule(),
- dataStoreModule(),
-
- uninitModule(httpFactory = platformHttpEngineFactory)
- )
- }) {
- val koin = getKoin()
- val prefs = koin.get()
- val genesisClient = koin.get()
- val dataStore = koin.get()
-
- val logLevel by prefs.preference("debug.logLevel", LogLevel.INFO.name)
-
- genesisClient.logLevel = LogLevel.fromName(logLevel)
-
-
- val themeName by remember { prefs.preference("ui.theme", "Catppuccin Mocha Rosewater") }
- ThemeProvider(
- themeName = themeName,
- ) {
- Scaffold(
- modifier = Modifier.fillMaxSize()
- .background(LocalContextColors.currentOrThrow.background),
- ) {
- Layout(
- measurePolicy = { measurables, constraints ->
- if (constraints.maxHeight > constraints.maxWidth && !dataStore.mobileUi) dataStore.mobileUi =
- true
- if (constraints.maxHeight < constraints.maxWidth && dataStore.mobileUi) dataStore.mobileUi =
- false
- val placeables = measurables.map { measurable ->
- measurable.measure(constraints)
- }
-
- layout(constraints.maxWidth, constraints.maxHeight) {
- var yPosition = 0
- placeables.forEach { placeable ->
- placeable.placeRelative(x = 0, y = yPosition)
- yPosition += placeable.height
- }
- }
- },
- content = {
- Box(Modifier.padding(it)) {
- Navigator(RootScreen())
- }
- }
- )
- }
- }
- }
-
-}
-
-expect fun getPlatformName(): String
-
-expect fun getAntiLog(): Antilog
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/Util.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/Util.kt
deleted file mode 100644
index 8279016..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/Util.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package uninit.genesis.app
-
-import cafe.adriel.voyager.navigator.Navigator
-import org.koin.core.Koin
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.di.dataStoreModule
-import uninit.genesis.app.di.genesisApiModule
-import uninit.genesis.app.di.genesisClientModule
-import uninit.genesis.app.ui.screens.RootScreen
-
-fun ReloadClient(koin: Koin, nav: Navigator) {
- var parent: Navigator = nav.parent!!
- while (parent.level != 0) {
- parent = parent.parent!!
- }
-
- val genesisClient = koin.get()
- genesisClient.gateway.disconnect()
-
- val oldDataStore = koin.get()
-
- koin.unloadModules(listOf(genesisClientModule(), genesisApiModule(), dataStoreModule()))
- koin.loadModules(listOf(genesisClientModule(), genesisApiModule(), dataStoreModule()))
-
- val newDataStore = koin.get()
-
- // Values that are necessary to transfer
- newDataStore.mobileUi = oldDataStore.mobileUi
-
- parent.replace(RootScreen())
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/data/DataStore.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/data/DataStore.kt
deleted file mode 100644
index 8ece0fc..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/data/DataStore.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package uninit.genesis.app.data
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import uninit.common.compose.fytix.ComposableEventBus
-import uninit.common.getTimeInMillis
-import uninit.genesis.app.ui.screens.client.ClientTab
-import uninit.genesis.discord.api.types.Snowflake
-
-class DataStore() : ComposableEventBus("DataStore") {
-
- var mobileUi by mutableStateOf(false)
- val shiggyEasterEgg by mutableStateOf(getTimeInMillis() % 10 == 0L)
-
-
- /**
- * Explicit typing for [emit] function, event is [Snowflake]
- */
- fun selectGuild(guildId: Snowflake) = emit("GUILD_SELECT", guildId)
-
- /**
- * Explicit typing for [on] function, event is [Snowflake]
- */
- fun onGuildSelect(block: Event.(Snowflake) -> Unit) =
- on("GUILD_SELECT", block)
-
- /**
- * Explicit typing for [compositionLocalOn] function, event is [Snowflake]
- */
- @Composable
- fun compositionOnGuildSelect(block: Event.(Snowflake) -> Unit) =
- compositionLocalOn("GUILD_SELECT", block)
-
- /**
- * Explicit typing for [emit] function, event is [Snowflake]
- */
- fun selectChannel(channelId: Snowflake) = emit("CHANNEL_SELECT", channelId)
-
- /**
- * Explicit typing for [on] function, event is [Snowflake]
- */
- fun onChannelSelect(block: Event.(Snowflake) -> Unit) =
- on("CHANNEL_SELECT", block)
-
- /**
- * Explicit typing for [compositionLocalOn] function, event is [Snowflake]
- */
- @Composable
- fun compositionOnChannelSelect(block: Event.(Snowflake) -> Unit) =
- compositionLocalOn("CHANNEL_SELECT", block)
-
- /**
- * Explicit typing for [emit] function, event is [ClientTab]
- */
- fun selectClientTab(tab: ClientTab) = emit("CLIENT_TAB_SELECT", tab)
-
- /**
- * Explicit typing for [on] function, event is [ClientTab]
- */
- fun onClientTabSelect(block: Event.(ClientTab) -> Unit) =
- on("CLIENT_TAB_SELECT", block)
-
- /**
- * Explicit typing for [compositionLocalOn] function, event is [ClientTab]
- */
- @Composable
- fun compositionOnClientTabSelect(block: Event.(ClientTab) -> Unit) =
- compositionLocalOn("CLIENT_TAB_SELECT", block)
-
- /**
- * Explicit typing for [emit] function, event is [Boolean]
- */
- fun toggleGuilds() = emit("GUILDS_TOGGLE", true)
-
- /**
- * Explicit typing for [on] function, event is [Boolean]
- */
- fun onToggleGuilds(block: Event.(Boolean) -> Unit) =
- on("GUILDS_TOGGLE", block)
-
- /**
- * Explicit typing for [compositionLocalOn] function, event is [Boolean]
- */
- @Composable
- fun compositionOnToggleGuilds(block: Event.(Boolean) -> Unit) =
- compositionLocalOn("GUILDS_TOGGLE", block)
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/dataStoreModule.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/dataStoreModule.kt
deleted file mode 100644
index 202a03b..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/dataStoreModule.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package uninit.genesis.app.di
-
-import org.koin.dsl.module
-import uninit.genesis.app.data.DataStore
-
-
-fun dataStoreModule() = module {
- single { DataStore() }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/genesisApiModule.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/genesisApiModule.kt
deleted file mode 100644
index 6b7fd05..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/genesisApiModule.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package uninit.genesis.app.di
-
-import org.koin.dsl.module
-import uninit.genesisApi.GenesisApiClient
-
-
-fun genesisApiModule() = module {
- single { GenesisApiClient(get()) }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/genesisClientModule.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/genesisClientModule.kt
deleted file mode 100644
index b920b78..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/genesisClientModule.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package uninit.genesis.app.di
-
-import org.koin.dsl.module
-import uninit.genesis.discord.client.GenesisClient
-
-
-fun genesisClientModule() = module {
- single { GenesisClient(get()) }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.kt
deleted file mode 100644
index b1f9ffe..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package uninit.genesis.app.di
-
-import io.ktor.client.engine.*
-import org.koin.dsl.module
-
-
-fun httpModule() = module {
- single { platformHttpEngineFactory }
-}
-
-expect val platformHttpEngineFactory: HttpClientEngineFactory<*>
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.kt
deleted file mode 100644
index c3f86f2..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package uninit.genesis.app.di
-
-import androidx.compose.runtime.Composable
-import org.koin.core.module.Module
-
-@Composable
-expect fun preferencesModule(): Module
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/LocalContextColors.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/LocalContextColors.kt
deleted file mode 100644
index 97d3c8f..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/LocalContextColors.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package uninit.genesis.app.theme
-
-import androidx.compose.material3.ColorScheme
-import androidx.compose.runtime.compositionLocalOf
-
-val LocalContextColors = compositionLocalOf { null }
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/Theme.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/Theme.kt
deleted file mode 100644
index bb653d4..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/Theme.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-package uninit.genesis.app.theme
-
-import androidx.compose.material3.ColorScheme
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Shapes
-import androidx.compose.material3.Typography
-import androidx.compose.runtime.Composable
-import uninit.genesis.app.theme.loader.ColorSchemeSerializable
-
-abstract class Theme(public val name: String) {
- @Composable
- abstract fun getColors(): ColorScheme
-
- @Composable
- fun getTypography(): Typography {
- return MaterialTheme.typography
- }
-
- @Composable
- fun getShapes(): Shapes {
- return MaterialTheme.shapes
- }
-
- companion object {
- fun fromCS(name: String, colors: ColorSchemeSerializable): Theme {
- return object : Theme(name) {
- @Composable
- override fun getColors(): ColorScheme {
- return ColorScheme(
- colors.primary,
- colors.onPrimary,
- colors.primaryContainer,
- colors.onPrimaryContainer,
- colors.inversePrimary,
- colors.secondary,
- colors.onSecondary,
- colors.secondaryContainer,
- colors.onSecondaryContainer,
- colors.tertiary,
- colors.onTertiary,
- colors.tertiaryContainer,
- colors.onTertiaryContainer,
- colors.background,
- colors.onBackground,
- colors.surface,
- colors.onSurface,
- colors.surfaceVariant,
- colors.onSurfaceVariant,
- colors.surfaceTint,
- colors.inverseSurface,
- colors.inverseOnSurface,
- colors.error,
- colors.onError,
- colors.errorContainer,
- colors.onErrorContainer,
- colors.outline,
- colors.outlineVariant,
- colors.scrim,
- )
- }
- }
-
- }
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/ThemeProvider.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/ThemeProvider.kt
deleted file mode 100644
index efe1706..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/ThemeProvider.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package uninit.genesis.app.theme
-
-import androidx.compose.material3.ColorScheme
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import uninit.genesis.app.theme.builtin.AllThemes
-import uninit.genesis.app.theme.builtin.Catppuccin
-
-@Composable
-fun ThemeProvider(
- theme: Theme = Catppuccin.Mocha.Rosewater,
- themeName: String? = null,
- colorScheme: ColorScheme = theme.getColors(), content: @Composable (ColorScheme.() -> Unit)
-) {
- var computedTheme = theme
- if (themeName != null) {
- computedTheme = AllThemes.find { it.name == themeName } ?: computedTheme
- }
- MaterialTheme(
- colorScheme = computedTheme.getColors(),
- typography = computedTheme.getTypography(),
- shapes = computedTheme.getShapes(),
- ) {
- CompositionLocalProvider(
- LocalContextColors provides colorScheme
- ) {
- computedTheme.getColors().content()
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/AllThemes.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/AllThemes.kt
deleted file mode 100644
index 8886998..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/AllThemes.kt
+++ /dev/null
@@ -1,48 +0,0 @@
- package uninit.genesis.app.theme.builtin
-
-// catppuccin.mocha.* is a theme
-val AllThemes = listOf(
- DefaultMaterialTheme,
- Catppuccin.Latte.Lavender,
- Catppuccin.Latte.Blue,
- Catppuccin.Latte.Sapphire,
- Catppuccin.Latte.Sky,
- Catppuccin.Latte.Teal,
- Catppuccin.Latte.Green,
- Catppuccin.Latte.Yellow,
- Catppuccin.Latte.Peach,
- Catppuccin.Latte.Maroon,
- Catppuccin.Latte.Red,
- Catppuccin.Latte.Mauve,
- Catppuccin.Latte.Pink,
- Catppuccin.Latte.Flamingo,
- Catppuccin.Latte.Rosewater,
- Catppuccin.Frappe.Lavender,
- Catppuccin.Frappe.Blue,
- Catppuccin.Frappe.Sapphire,
- Catppuccin.Frappe.Sky,
- Catppuccin.Frappe.Teal,
- Catppuccin.Frappe.Green,
- Catppuccin.Frappe.Yellow,
- Catppuccin.Frappe.Peach,
- Catppuccin.Frappe.Maroon,
- Catppuccin.Frappe.Red,
- Catppuccin.Frappe.Mauve,
- Catppuccin.Frappe.Pink,
- Catppuccin.Frappe.Flamingo,
- Catppuccin.Frappe.Rosewater,
- Catppuccin.Macchiato.Lavender,
- Catppuccin.Macchiato.Blue,
- Catppuccin.Macchiato.Sapphire,
- Catppuccin.Macchiato.Sky,
- Catppuccin.Macchiato.Teal,
- Catppuccin.Macchiato.Green,
- Catppuccin.Macchiato.Yellow,
- Catppuccin.Macchiato.Peach,
- Catppuccin.Macchiato.Maroon,
- Catppuccin.Macchiato.Red,
- Catppuccin.Macchiato.Mauve,
- Catppuccin.Macchiato.Pink,
- Catppuccin.Macchiato.Flamingo,
- Catppuccin.Macchiato.Rosewater
-)
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/Catppuccin.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/Catppuccin.kt
deleted file mode 100644
index 2a64683..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/Catppuccin.kt
+++ /dev/null
@@ -1,312 +0,0 @@
-package uninit.genesis.app.theme.builtin
-
-import androidx.compose.material3.ColorScheme
-import androidx.compose.material3.darkColorScheme
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.graphics.Color
-import uninit.common.LinearGradient
-import uninit.common.color
-import uninit.common.linearGradient
-import uninit.genesis.app.theme.Theme
-
-object Catppuccin {
- internal fun flavorToTheme(
- name: String,
- flavor: Flavor,
- primaryColor: Color,
- secondaryColor: Color,
- tertiaryColor: Color,
- errorColor: Color
- ): Lazy {
- return lazy {
- object : Theme("Catppuccin $name") {
- @Composable
- override fun getColors(): ColorScheme {
- fun gradientFrom(color: Color): LinearGradient {
- return@gradientFrom linearGradient(
- color(LinearGradient.RGBA.BLACK, 0F),
- color(
- (color.red * 255f).toInt(),
- (color.green * 255f).toInt(),
- (color.blue * 255f).toInt(),
- (color.alpha * 255f).toInt(),
- 40F
- ),
- color(LinearGradient.RGBA.WHITE, 100F)
- )
- }
- fun LinearGradient.RGBA.color(): Color {
- return@color Color(
- this.r.coerceIn(0..255),
- this.g.coerceIn(0..255),
- this.b.coerceIn(0..255),
- this.a.coerceIn(0..255)
- )
- }
- val primary = gradientFrom(primaryColor)
- val secondary = gradientFrom(secondaryColor)
- val tertiary = gradientFrom(tertiaryColor)
- val error = gradientFrom(errorColor)
-
- val neutral = gradientFrom(flavor.Surface0)
- val neutralVariant = gradientFrom(flavor.Surface1)
- return darkColorScheme(
- primary = flavor.Surface0,
- onPrimary = flavor.Text,
- primaryContainer = primary[90F].color(),
- onPrimaryContainer = primary[10F].color(),
- secondary = secondary[40F].color(),
- onSecondary = secondary[100F].color(),
- secondaryContainer = secondary[90F].color(),
- onSecondaryContainer = secondary[10F].color(),
- tertiary = tertiary[40F].color(),
- onTertiary = tertiary[100F].color(),
- tertiaryContainer = tertiary[90F].color(),
- onTertiaryContainer = tertiary[10F].color(),
- error = error[40F].color(),
- onError = error[100F].color(),
- errorContainer = error[90F].color(),
- onErrorContainer = error[10F].color(),
- surface = neutral[40F].color(),
- onSurface = neutral[100F].color(),
- surfaceVariant = neutralVariant[40F].color(),
- onSurfaceVariant = neutralVariant[100F].color(),
- background = flavor.Crust,
- onBackground = Color.White,
- surfaceTint = primary[40F].color(),
-
- )
- }
- }
- }
- }
-
- sealed class Flavor(
- val Crust: Color,
- val Mantle: Color,
- val Base: Color,
-
- val Surface0: Color,
- val Surface1: Color,
- val Surface2: Color,
-
- val Overlay0: Color,
- val Overlay1: Color,
- val Overlay2: Color,
-
- val Subtext0: Color,
- val Subtext1: Color,
-
- val Text: Color,
-
- val Lavender: Color,
- val Blue: Color,
- val Sapphire: Color,
- val Sky: Color,
- val Teal: Color,
- val Green: Color,
- val Yellow: Color,
- val Peach: Color,
- val Maroon: Color,
- val Red: Color,
- val Mauve: Color,
- val Pink: Color,
- val Flamingo: Color,
- val Rosewater: Color,
- )
-
- sealed class ThemePack(name: String, flavor: Flavor) {
- val Lavender by flavorToTheme(
- "$name Lavender",
- flavor,
- flavor.Lavender,
- flavor.Sapphire,
- flavor.Teal,
- flavor.Red
- )
- val Blue by flavorToTheme("$name Blue", flavor, flavor.Blue, flavor.Sky, flavor.Green, flavor.Maroon)
- val Sapphire by flavorToTheme("$name Sapphire", flavor, flavor.Sapphire, flavor.Teal, flavor.Yellow, flavor.Red)
- val Sky by flavorToTheme("$name Sky", flavor, flavor.Sky, flavor.Green, flavor.Peach, flavor.Maroon)
- val Teal by flavorToTheme("$name Teal", flavor, flavor.Teal, flavor.Yellow, flavor.Maroon, flavor.Red)
- val Green by flavorToTheme("$name Green", flavor, flavor.Green, flavor.Peach, flavor.Red, flavor.Maroon)
- val Yellow by flavorToTheme("$name Yellow", flavor, flavor.Yellow, flavor.Maroon, flavor.Mauve, flavor.Red)
- val Peach by flavorToTheme("$name Peach", flavor, flavor.Peach, flavor.Red, flavor.Pink, flavor.Maroon)
- val Maroon by flavorToTheme("$name Maroon", flavor, flavor.Maroon, flavor.Mauve, flavor.Flamingo, flavor.Red)
- val Red by flavorToTheme("$name Red", flavor, flavor.Red, flavor.Pink, flavor.Rosewater, flavor.Maroon)
- val Mauve by flavorToTheme("$name Mauve", flavor, flavor.Mauve, flavor.Flamingo, flavor.Lavender, flavor.Red)
- val Pink by flavorToTheme("$name Pink", flavor, flavor.Pink, flavor.Rosewater, flavor.Blue, flavor.Maroon)
- val Flamingo by flavorToTheme(
- "$name Flamingo",
- flavor,
- flavor.Flamingo,
- flavor.Lavender,
- flavor.Sapphire,
- flavor.Red
- )
- val Rosewater by flavorToTheme(
- "$name Rosewater",
- flavor,
- flavor.Rosewater,
- flavor.Blue,
- flavor.Sky,
- flavor.Maroon
- )
- }
-
- @PublishedApi
- internal data object LatteFlavor : Flavor(
- Crust = Color(0xFFdce0e8),
- Mantle = Color(0xFFe6e9ef),
- Base = Color(0xFFeff1f5),
-
- Surface0 = Color(0xFFccd0da),
- Surface1 = Color(0xFFbcc0cc),
- Surface2 = Color(0xFFacb0be),
-
- Overlay0 = Color(0xFF9ca0b0),
- Overlay1 = Color(0xFF8c8fa1),
- Overlay2 = Color(0xFF7c7f93),
-
- Subtext0 = Color(0xFF6c6f85),
- Subtext1 = Color(0xFF5c5f77),
-
- Text = Color(0xFF4c4f69),
-
- Lavender = Color(0xFF7287fd),
- Blue = Color(0xFF1e66f5),
- Sapphire = Color(0xFF209fb5),
- Sky = Color(0xFF04a5e5),
- Teal = Color(0xFF179299),
- Green = Color(0xFF40a02b),
- Yellow = Color(0xFFdf8e1d),
- Peach = Color(0xFFfe640b),
- Maroon = Color(0xFFe64553),
- Red = Color(0xFFd20f39),
- Mauve = Color(0xFF8839ef),
- Pink = Color(0xFFea76cb),
- Flamingo = Color(0xFFdd7878),
- Rosewater = Color(0xFFdc8a78)
- )
-
- @PublishedApi
- internal data object FrappeFlavor : Flavor(
- Crust = Color(0xFF232634),
- Mantle = Color(0xFF292c3c),
- Base = Color(0xFF414559),
-
- Surface0 = Color(0xFF414559),
- Surface1 = Color(0xFF51576d),
- Surface2 = Color(0xFF626880),
-
- Overlay0 = Color(0xFF737994),
- Overlay1 = Color(0xFF838ba7),
- Overlay2 = Color(0xFF949cbb),
-
- Subtext0 = Color(0xFFa5adce),
- Subtext1 = Color(0xFFb5bfe2),
-
- Text = Color(0xFFc6d0f5),
-
- Lavender = Color(0xFFbabbf1),
- Blue = Color(0xFF8caaee),
- Sapphire = Color(0xFF85c1dc),
- Sky = Color(0xFF99d1db),
- Teal = Color(0xFF81c8be),
- Green = Color(0xFFa6d189),
- Yellow = Color(0xFFe5c890),
- Peach = Color(0xFFef9f76),
- Maroon = Color(0xFFea999c),
- Red = Color(0xFFe78284),
- Mauve = Color(0xFFca9ee6),
- Pink = Color(0xFFf4b8e4),
- Flamingo = Color(0xFFeebebe),
- Rosewater = Color(0xFFf2d5cf)
- )
-
- @PublishedApi
- internal object MacchiatoFlavor : Flavor(
- Crust = Color(0xFF181926),
- Mantle = Color(0xFF1e2030),
- Base = Color(0xFF24273a),
-
- Surface0 = Color(0xFF363a4f),
- Surface1 = Color(0xFF494d64),
- Surface2 = Color(0xFF5b6078),
-
- Overlay0 = Color(0xFF6e738d),
- Overlay1 = Color(0xFF8087a2),
- Overlay2 = Color(0xFF939ab7),
-
- Subtext0 = Color(0xFFa5adcb),
- Subtext1 = Color(0xFFb8c0e0),
-
- Text = Color(0xFFcad3f5),
-
- Lavender = Color(0xFFb7bdf8),
- Blue = Color(0xFF8aadf4),
- Sapphire = Color(0xFF7dc4e4),
- Sky = Color(0xFF91d7e3),
- Teal = Color(0xFF8bd5ca),
- Green = Color(0xFFa6da95),
- Yellow = Color(0xFFeed49f),
- Peach = Color(0xFFf5a97f),
- Maroon = Color(0xFFee99a0),
- Red = Color(0xFFed8796),
- Mauve = Color(0xFFc6a0f6),
- Pink = Color(0xFFf5bde6),
- Flamingo = Color(0xFFf0c6c6),
- Rosewater = Color(0xFFf4dbd6)
- )
-
- @PublishedApi
- internal object MochaFlavor : Flavor(
- Crust = Color(0xFF11111b),
- Mantle = Color(0xFF181825),
- Base = Color(0xFF1e1e2e),
-
- Surface0 = Color(0xFF313244),
- Surface1 = Color(0xFF45475a),
- Surface2 = Color(0xFF585b70),
-
- Overlay0 = Color(0xFF6c7086),
- Overlay1 = Color(0xFF7f849c),
- Overlay2 = Color(0xFF9399b2),
-
- Subtext0 = Color(0xFFa6adc8),
- Subtext1 = Color(0xFFbac2de),
-
- Text = Color(0xFFcdd6f4),
-
- Lavender = Color(0xFFb4befe),
- Blue = Color(0xFF89b4fa),
- Sapphire = Color(0xFF74c7ec),
- Sky = Color(0xFF89dceb),
- Teal = Color(0xFF94e2d5),
- Green = Color(0xFFa6e3a1),
- Yellow = Color(0xFFf9e2af),
- Peach = Color(0xFFfab387),
- Maroon = Color(0xFFeba0ac),
- Red = Color(0xFFf38ba8),
- Mauve = Color(0xFFcba6f7),
- Pink = Color(0xFFf5c2e7),
- Flamingo = Color(0xFFf2cdcd),
- Rosewater = Color(0xFFf5e0dc)
- )
-
- object Latte : ThemePack("Latte", LatteFlavor)
- object Frappe : ThemePack("Frappe", FrappeFlavor)
- object Macchiato : ThemePack("Macchiato", MacchiatoFlavor)
- object Mocha : ThemePack("Mocha", MochaFlavor)
-
- object Flavors {
- inline val Latte: Flavor
- get() = LatteFlavor
- inline val Frappe: Flavor
- get() = FrappeFlavor
- inline val Macchiato: Flavor
- get() = MacchiatoFlavor
- inline val Mocha: Flavor
- get() = MochaFlavor
- }
-
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/DefaultMaterialTheme.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/DefaultMaterialTheme.kt
deleted file mode 100644
index b5b9e0b..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/builtin/DefaultMaterialTheme.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package uninit.genesis.app.theme.builtin
-
-import androidx.compose.material3.ColorScheme
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import uninit.genesis.app.theme.Theme
-
-object DefaultMaterialTheme : Theme("Default Material Theme") {
- @Composable
- override fun getColors(): ColorScheme {
- return MaterialTheme.colorScheme
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/loader/ColorSchemeSerializable.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/loader/ColorSchemeSerializable.kt
deleted file mode 100644
index 134406a..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/theme/loader/ColorSchemeSerializable.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package uninit.genesis.app.theme.loader
-
-import androidx.compose.ui.graphics.Color
-
-
-data class ColorSchemeSerializable(
- val primary: Color,
- val onPrimary: Color,
- val primaryContainer: Color,
- val onPrimaryContainer: Color,
- val inversePrimary: Color,
- val secondary: Color,
- val onSecondary: Color,
- val secondaryContainer: Color,
- val onSecondaryContainer: Color,
- val tertiary: Color,
- val onTertiary: Color,
- val tertiaryContainer: Color,
- val onTertiaryContainer: Color,
- val background: Color,
- val onBackground: Color,
- val surface: Color,
- val onSurface: Color,
- val surfaceVariant: Color,
- val onSurfaceVariant: Color,
- val surfaceTint: Color,
- val inverseSurface: Color,
- val inverseOnSurface: Color,
- val error: Color,
- val onError: Color,
- val errorContainer: Color,
- val onErrorContainer: Color,
- val outline: Color,
- val outlineVariant: Color,
- val scrim: Color,
-)
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/BackArrow.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/BackArrow.kt
deleted file mode 100644
index 6dd84c4..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/BackArrow.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package uninit.genesis.app.ui.components
-
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.Navigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-
-@Composable
-fun BoxScope.BackArrow(
- onClick: (() -> Unit)? = null,
- navigator: Navigator? = LocalNavigator.currentOrThrow,
-) {
- Box(
- modifier = androidx.compose.ui.Modifier
- .fillMaxSize()
- .align(Alignment.TopStart)
- ) {
- TextButton(
- onClick = {
- if (onClick != null) {
- onClick()
- } else {
- navigator?.pop()
- }
- },
- ) {
- Text("<")
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/Centered.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/Centered.kt
deleted file mode 100644
index 2ea42cb..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/Centered.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package uninit.genesis.app.ui.components
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-
-@Composable
-inline fun Centered(
- modifier: Modifier = Modifier.fillMaxSize(),
- crossinline content: @Composable () -> Unit
-) {
- Scaffold {pv ->
- Column(
- modifier
- .padding(pv),
- verticalArrangement = Arrangement.Center,
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- content()
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/User/Avatar.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/User/Avatar.kt
deleted file mode 100644
index 428facd..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/User/Avatar.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package uninit.genesis.app.ui.components.User
-
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.unit.dp
-import io.github.aakira.napier.Napier
-import io.kamel.image.KamelImage
-import org.jetbrains.compose.resources.ExperimentalResourceApi
-import org.jetbrains.compose.resources.painterResource
-import uninit.genesis.discord.client.entities.guild.User
-
-@OptIn(ExperimentalResourceApi::class)
-@Composable
-fun Avatar(author: User, modifier: Modifier = Modifier) {
- Box(
- modifier = modifier
- .width(32.dp)
- .height(32.dp)
- .clip(shape = CircleShape)
- ) {
- val defaultAvatar = painterResource("images/defaults/default_avatar_${author.id % 5}.png")
- if (author.avatar != null) {
- KamelImage(
- resource = author.avatar!!.render(128),
- contentDescription = "Avatar",
- onLoading = {
- Image(
- painter = defaultAvatar,
- contentDescription = "Avatar Loading",
- )
- },
- onFailure = {
- Napier.e(
- "Avatar for ${author.displayName} failed to load",
- it,
- "Avatar Component"
- )
- Image(
- painter = defaultAvatar,
- contentDescription = "Avatar Failed to load",
- )
- }
- )
- } else {
- Image(
- painter = defaultAvatar,
- contentDescription = "Avatar",
- )
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/Form.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/Form.kt
deleted file mode 100644
index 1ccae6e..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/Form.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package uninit.genesis.app.ui.components.form
-
-import androidx.compose.foundation.layout.Column
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-
-open class Form(val fields: List>, val onSubmitV: (Map.() -> Unit)?, val submitText: String) {
- @Composable
- open fun compose() {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- for (field in fields) {
- field.compose()
- }
- Button(
- onClick = {
- onSubmitV?.invoke(fields.associate { it.id to it.value.value!! })
- }
- ) {
- Text(submitText)
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/FormBuilder.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/FormBuilder.kt
deleted file mode 100644
index a064908..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/FormBuilder.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-package uninit.genesis.app.ui.components.form
-
-import androidx.compose.runtime.Composable
-
-open class FormBuilder() {
- internal val fields: MutableList> = mutableListOf()
- var onSubmitV: (Map.() -> Unit)? = null
- var submitText: String = "Submit"
- fun text(
- id: String,
- label: String,
- ) {
- val field = FormItem.Text(id, label)
- fields.add(field)
- }
-
- fun password(
- id: String,
- label: String,
- ) {
- val field = FormItem.Password(id, label)
- fields.add(field)
- }
-
- fun switch(
- id: String,
- label: String,
- ) {
- val field = FormItem.Switch(id, label)
- fields.add(field)
- }
-
- fun select(
- id: String,
- label: String,
- options: List,
- ) {
- val field = FormItem.MultiSelect(id, label, options)
- fields.add(field)
- }
-
- fun radio(
- id: String,
- label: String,
- options: List,
- ) {
- val field = FormItem.Radio(id, label, options)
- fields.add(field)
- }
-
- fun number(
- id: String,
- label: String,
- ) {
- val field = FormItem.Number(id, label)
- fields.add(field)
- }
-
- fun separator(
- id: String,
- label: String,
- ) {
- val field = FormItem.Separator(id, label)
- fields.add(field)
- }
-
- open fun build(): Form {
- return Form(fields, onSubmitV, submitText)
- }
-
- open fun onSubmit(
- onSubmit: Map.() -> Unit,
- ) {
- onSubmitV = onSubmit
- }
-
- fun assignSubmitText(
- submitText: String,
- ) {
- this.submitText = submitText
- }
-
- fun animatedToggleTwoSides(
- block: FormBuilder.() -> Unit, // m
- ) {
-
- }
-}
-
-fun buildForm(
- builder: FormBuilder.() -> Unit,
-): Form {
- val formBuilder = FormBuilder()
- formBuilder.builder()
- return formBuilder.build()
-}
-
-@Composable
-fun composeForm(
- builder: FormBuilder.() -> Unit
-) {
- val formBuilder = FormBuilder()
- formBuilder.builder()
- val form = formBuilder.build()
- form.compose()
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/FormItem.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/FormItem.kt
deleted file mode 100644
index 7f61e58..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/form/FormItem.kt
+++ /dev/null
@@ -1,344 +0,0 @@
-package uninit.genesis.app.ui.components.form
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.Checkbox
-import androidx.compose.material3.Divider
-import androidx.compose.material3.RadioButton
-import androidx.compose.material3.Switch
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextField
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.input.PasswordVisualTransformation
-import androidx.compose.ui.unit.dp
-import uninit.common.compose.inverse
-
-interface FormItem {
- val id: String
- val label: String
- val value: MutableState
-
- @Composable
- fun compose()
- open class Text(
- override val id: String,
- override val label: String,
- ) : FormItem {
- override val value = mutableStateOf("")
-
- @Composable
- override fun compose() {
- TextField(
- value = value.value,
- onValueChange = {
- value.value = it
- },
- label = {
- Text(label)
- },
- singleLine = true,
- modifier = Modifier.padding(vertical = 8.dp)
- )
- }
- }
-
- class Password(id: String, label: String) : Text(id, label) {
- @Composable
- override fun compose() {
- TextField(
- value = value.value,
- onValueChange = {
- value.value = it
- },
- label = {
- Text(label)
- },
- singleLine = true,
- visualTransformation = PasswordVisualTransformation(),
- modifier = Modifier.padding(vertical = 8.dp)
- )
- }
- }
-
- class Switch(
- override val id: String,
- override val label: String,
- ) : FormItem {
- override val value = mutableStateOf(false)
-
- @Composable
- override fun compose() {
- Row(
- horizontalArrangement = Arrangement.SpaceBetween,
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Text(
- label,
- modifier = Modifier.padding(vertical = 8.dp, horizontal = 1.dp)
- )
- Switch(
- checked = value.value,
- onCheckedChange = {
- value.value = it
- },
- modifier = Modifier.padding(vertical = 8.dp, horizontal = 1.dp)
- )
- }
- }
- }
-
- class MultiSelect(
- override val id: String,
- override val label: String,
- val options: List,
- ) : FormItem> {
- override val value = mutableStateOf(listOf(options.first()))
-
- @Composable
- override fun compose() {
-
- LazyColumn {
- items(options.size) { index ->
- Checkbox(
- checked = value.value.contains(options[index]),
- onCheckedChange = {
- if (it) {
- value.value += options[index]
- } else {
- value.value -= options[index]
- }
- },
- modifier = Modifier.padding(vertical = 8.dp)
- )
- }
- }
-
- }
- }
-
- class Radio(
- override val id: String,
- override val label: String,
- val options: List,
- ) : FormItem {
- override val value = mutableStateOf(options.first())
-
- @Composable
- override fun compose() {
-
- LazyColumn {
- items(options.size) { index ->
- RadioButton(
- selected = value.value == options[index],
- onClick = {
- value.value = options[index]
- },
- modifier = Modifier.padding(vertical = 8.dp)
- )
- }
- }
-
- }
- }
-
- class Number(
- override val id: String,
- override val label: String,
- ) : FormItem {
- override val value = mutableStateOf(0)
-
- @Composable
- override fun compose() {
- TextField(
- value = value.value.toString(),
- onValueChange = {
- try {
- if (it.isNotEmpty()) {
- value.value = it.toInt()
- }
- } catch (_: Exception) {
-
- }
- },
- label = {
- Text(label)
- },
- singleLine = true,
- modifier = Modifier.padding(vertical = 8.dp)
- )
- }
- }
-
- class Separator(
- override val id: String,
- override val label: String,
- ) : FormItem {
- override val value = mutableStateOf(Unit)
-
- @Composable
- override fun compose() {
- Row(
- horizontalArrangement = Arrangement.Center,
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier.fillMaxWidth(0.6f)
- ) {
- if (label.isNotEmpty()) {
- Divider(
- thickness = 1.dp,
- color = Color.LightGray,
- modifier = Modifier.padding(vertical = 8.dp, horizontal = 1.dp).weight(0.3f)
- )
- Text(label, Modifier)
- Divider(
- thickness = 1.dp,
- color = Color.LightGray,
- modifier = Modifier.padding(vertical = 8.dp, horizontal = 1.dp).weight(0.3f)
- )
- } else {
- Divider(
- thickness = 1.dp,
- color = Color.LightGray,
- modifier = Modifier.padding(vertical = 8.dp, horizontal = 0.dp)
- .fillMaxWidth()
- )
- }
- }
- }
- }
-
-
- class TwoSidedForm(
- builder: TwoSidedFormBuilder.() -> Unit,
- override val id: String,
- ) : FormItem>> {
- private val ctx: TwoSidedFormContext = TwoSidedFormBuilder().apply(builder).build()
- override val label: String = ""
- override val value: MutableState>> =
- mutableStateOf(mutableMapOf())
-
- inner class TwoSidedFormBuilder(
- val mutableOpenState: MutableState = mutableStateOf(
- true
- )
- ) {
-
- lateinit var left: TwoSidedFormSideForm
- lateinit var right: TwoSidedFormSideForm
-
- inner class TwoSidedFormSideBuilder(
- val id: String,
- val mutableOpenState: MutableState,
- val left: Boolean
- ) : FormBuilder() {
- inner class HeadItem(override val label: String) : FormItem {
- override val id: String = ""
- override val value: MutableState = mutableStateOf(Unit)
-
- @Composable
- override fun compose() {
- TODO()
- }
- }
-
- inner class SwapItem(
- override val label: String,
- val swapMutableState: MutableState
- ) : FormItem {
- override val id: String = ""
- override val value: MutableState = mutableStateOf(Unit)
-
- @Composable
- override fun compose() {
- TODO()
- }
- }
-
- fun head(
- label: String,
- ) {
- val field = HeadItem(label)
- fields.add(field)
- }
-
- fun swap(
- label: String,
- ) {
- if (left) {
- fields.add(
- SwapItem(label, mutableOpenState)
- )
- } else {
- fields.add(
- SwapItem(label, mutableOpenState.inverse())
- )
- }
- }
-
- override fun onSubmit(onSubmit: Map.() -> Unit) {
- error("Regular form onSubmit is not supported in twoSided form")
- }
-
- override fun build(): TwoSidedFormSideForm {
- return TwoSidedFormSideForm(id, fields, submitText, onSubmitV)
- }
- }
-
- inner class TwoSidedFormSideForm(
- override val id: String,
- formItems: List>,
- submitText: String,
- val onSubmitTSV: (MutableMap.() -> Unit)? = null,
-
- ) : FormItem>, Form(formItems, {}, submitText) {
- override val label: String = ""
- override val value: MutableState> =
- mutableStateOf(mutableMapOf())
-
- @Composable
- override fun compose() {
- TODO()
- }
- }
-
- fun left(
- id: String,
- builder: TwoSidedFormSideBuilder.() -> Unit,
- ) {
- left = TwoSidedFormSideBuilder(id, mutableOpenState, true).apply(builder).build()
- }
-
- fun right(
- id: String,
- builder: TwoSidedFormSideBuilder.() -> Unit,
- ) {
- right = TwoSidedFormSideBuilder(id, mutableOpenState, false).apply(builder).build()
- }
-
-
- fun build(): TwoSidedFormContext {
- TODO()
- }
- }
-
- inner class TwoSidedFormContext(
- val left: List>,
- val right: List>
- )
-
- @Composable
- override fun compose() {
- TODO()
-
-
- }
- }
-
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/guild/Message.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/guild/Message.kt
deleted file mode 100644
index a2e09fb..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/guild/Message.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-package uninit.genesis.app.ui.components.guild
-
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.defaultMinSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.unit.dp
-import io.kamel.image.KamelImage
-import io.kamel.image.asyncPainterResource
-import org.jetbrains.compose.resources.ExperimentalResourceApi
-import uninit.genesis.discord.client.entities.guild.Attachment
-import uninit.genesis.discord.client.entities.guild.AttachmentType
-import uninit.genesis.discord.client.entities.guild.Embed
-import uninit.genesis.discord.client.entities.guild.EmbedType
-import uninit.genesis.discord.client.entities.guild.Message
-import uninit.genesis.app.ui.components.User.Avatar
-
-@Composable
-fun messageEmbed(embed: Embed) {
- when (embed.type) {
- EmbedType.IMAGE ->
- KamelImage(
- asyncPainterResource(embed.image!!.displayUrl),
- modifier = Modifier
- .padding(top = 16.dp)
- .height(embed.image!!.height?.dp ?: 100.dp)
- .width(embed.image!!.width?.dp ?: 100.dp),
- contentDescription = null
- )
-
- else -> return
- }
-}
-
-@Composable
-fun messageAttachment(attachment: Attachment) {
- when (attachment.type) {
- AttachmentType.IMAGE ->
- KamelImage(
- asyncPainterResource(attachment.proxyUrl),
- modifier = Modifier
- .padding(top = 16.dp)
- .height(attachment.height!!.dp)
- .width(attachment.width!!.dp),
- contentDescription = null
- )
-
- else -> return
- }
-}
-
-@OptIn(ExperimentalResourceApi::class)
-@Composable
-fun message(message: Message) {
- Row(
- modifier = Modifier.fillMaxWidth()
- .defaultMinSize(minHeight = 48.dp),
- horizontalArrangement = Arrangement.spacedBy(16.dp)
- ) {
- Avatar(message.author)
- Column {
- Text(message.author.displayName)
- Text(
- message.content,
- color = if (message.isSent) MaterialTheme.colorScheme.onSurface else Color.Gray
- )
- message.attachments.forEach { messageAttachment(it) }
- message.embeds.forEach { messageEmbed(it) }
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/__Icons.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/__Icons.kt
deleted file mode 100644
index 9b36ea9..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/__Icons.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package uninit.genesis.app.ui.components.icons
-
-import androidx.compose.ui.graphics.vector.ImageVector
-import uninit.genesis.app.ui.components.icons.icons.Empty
-import uninit.genesis.app.ui.components.icons.icons.Textchannel
-import uninit.genesis.app.ui.components.icons.icons.Thread
-import kotlin.collections.List as ____KtList
-
-public object Icons
-
-private var __AllIcons: ____KtList? = null
-
-public val Icons.AllIcons: ____KtList
- get() {
- if (__AllIcons != null) {
- return __AllIcons!!
- }
- __AllIcons = listOf(Textchannel, Thread, Empty)
- return __AllIcons!!
- }
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Empty.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Empty.kt
deleted file mode 100644
index 0d59def..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Empty.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package uninit.genesis.app.ui.components.icons.icons
-
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.graphics.vector.ImageVector.Builder
-import androidx.compose.ui.unit.dp
-import uninit.genesis.app.ui.components.icons.Icons
-
-public val Icons.Empty: ImageVector
- get() {
- if (_empty != null) {
- return _empty!!
- }
- _empty = Builder(
- name = "Empty", defaultWidth = 24.0.dp, defaultHeight =
- 24.0.dp, viewportWidth = 24.0f, viewportHeight = 24.0f
- ).apply {
- }
- .build()
- return _empty!!
- }
-
-private var _empty: ImageVector? = null
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Textchannel.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Textchannel.kt
deleted file mode 100644
index 03fd6de..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Textchannel.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-package uninit.genesis.app.ui.components.icons.icons
-
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.PathFillType.Companion.EvenOdd
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
-import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.graphics.vector.ImageVector.Builder
-import androidx.compose.ui.graphics.vector.path
-import androidx.compose.ui.unit.dp
-import uninit.genesis.app.ui.components.icons.Icons
-
-public val Icons.Textchannel: ImageVector
- get() {
- if (_textchannel != null) {
- return _textchannel!!
- }
- _textchannel = Builder(name = "Textchannel", defaultWidth = 24.0.dp, defaultHeight =
- 24.0.dp, viewportWidth = 24.0f, viewportHeight = 24.0f).apply {
- path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f,
- strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
- pathFillType = EvenOdd) {
- moveTo(5.887f, 21.0f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.493f, -0.587f)
- lineTo(6.0f, 17.0f)
- horizontalLineTo(2.595f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.492f, -0.586f)
- lineToRelative(0.175f, -1.0f)
- arcTo(0.5f, 0.5f, 0.0f, false, true, 2.77f, 15.0f)
- horizontalLineToRelative(3.58f)
- lineToRelative(1.06f, -6.0f)
- horizontalLineTo(4.005f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.492f, -0.586f)
- lineToRelative(0.175f, -1.0f)
- arcTo(0.5f, 0.5f, 0.0f, false, true, 4.18f, 7.0f)
- horizontalLineToRelative(3.58f)
- lineToRelative(0.637f, -3.587f)
- arcTo(0.5f, 0.5f, 0.0f, false, true, 8.889f, 3.0f)
- horizontalLineToRelative(0.984f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, 0.493f, 0.587f)
- lineTo(9.76f, 7.0f)
- horizontalLineToRelative(6.0f)
- lineToRelative(0.637f, -3.587f)
- arcTo(0.5f, 0.5f, 0.0f, false, true, 16.889f, 3.0f)
- horizontalLineToRelative(0.984f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, 0.493f, 0.587f)
- lineTo(17.76f, 7.0f)
- horizontalLineToRelative(3.405f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, 0.492f, 0.586f)
- lineToRelative(-0.175f, 1.0f)
- arcTo(0.5f, 0.5f, 0.0f, false, true, 20.99f, 9.0f)
- horizontalLineToRelative(-3.58f)
- lineToRelative(-1.06f, 6.0f)
- horizontalLineToRelative(3.405f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, 0.492f, 0.586f)
- lineToRelative(-0.175f, 1.0f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.492f, 0.414f)
- horizontalLineTo(16.0f)
- lineToRelative(-0.637f, 3.587f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.492f, 0.413f)
- horizontalLineToRelative(-0.984f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.493f, -0.587f)
- lineTo(14.0f, 17.0f)
- horizontalLineTo(8.0f)
- lineToRelative(-0.637f, 3.587f)
- arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.492f, 0.413f)
- horizontalLineToRelative(-0.984f)
- close()
- moveTo(9.41f, 9.0f)
- lineToRelative(-1.06f, 6.0f)
- horizontalLineToRelative(6.0f)
- lineToRelative(1.06f, -6.0f)
- horizontalLineToRelative(-6.0f)
- close()
- }
- }
- .build()
- return _textchannel!!
- }
-
-private var _textchannel: ImageVector? = null
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Thread.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Thread.kt
deleted file mode 100644
index ee598c4..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/components/icons/icons/Thread.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package uninit.genesis.app.ui.components.icons.icons
-
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.PathFillType
-import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
-import androidx.compose.ui.graphics.StrokeJoin
-import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.graphics.vector.ImageVector.Builder
-import androidx.compose.ui.graphics.vector.path
-import androidx.compose.ui.unit.dp
-import uninit.genesis.app.ui.components.icons.Icons
-
-public val Icons.Thread: ImageVector
- get() {
- if (_thread != null) {
- return _thread!!
- }
- _thread = Builder(name = "Thread", defaultWidth = 24.0.dp, defaultHeight = 24.0.dp,
- viewportWidth = 24.0f, viewportHeight = 24.0f).apply {
- path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f,
- strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
- pathFillType = NonZero) {
- moveTo(5.433f, 21.0f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, -0.118f, -0.141f)
- lineTo(6.0f, 17.0f)
- horizontalLineTo(2.143f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, -0.118f, -0.14f)
- lineToRelative(0.308f, -1.76f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, 0.118f, -0.1f)
- horizontalLineTo(6.35f)
- lineToRelative(1.06f, -6.0f)
- horizontalLineTo(3.553f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, -0.118f, -0.14f)
- lineToRelative(0.308f, -1.76f)
- arcTo(0.12f, 0.12f, 0.0f, false, true, 3.86f, 7.0f)
- horizontalLineTo(7.76f)
- lineToRelative(0.692f, -3.901f)
- arcTo(0.12f, 0.12f, 0.0f, false, true, 8.57f, 3.0f)
- horizontalLineToRelative(1.757f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, 0.118f, 0.141f)
- lineTo(9.76f, 7.0f)
- horizontalLineToRelative(6.0f)
- lineToRelative(0.692f, -3.901f)
- arcTo(0.12f, 0.12f, 0.0f, false, true, 16.57f, 3.0f)
- horizontalLineToRelative(1.757f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, 0.118f, 0.141f)
- lineTo(17.76f, 7.0f)
- horizontalLineToRelative(3.857f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, 0.118f, 0.14f)
- lineToRelative(-0.308f, 1.76f)
- arcToRelative(0.12f, 0.12f, 0.0f, false, true, -0.118f, 0.1f)
- horizontalLineToRelative(-3.9f)
- lineToRelative(-0.36f, 2.04f)
- horizontalLineTo(15.05f)
- lineTo(15.41f, 9.0f)
- horizontalLineToRelative(-6.0f)
- lineToRelative(-1.06f, 6.0f)
- horizontalLineToRelative(2.21f)
- verticalLineToRelative(2.0f)
- horizontalLineTo(8.0f)
- lineToRelative(-0.693f, 3.901f)
- arcTo(0.12f, 0.12f, 0.0f, false, true, 7.19f, 21.0f)
- horizontalLineTo(5.433f)
- close()
- }
- path(fill = SolidColor(Color(0xFF000000)), stroke = null, strokeLineWidth = 0.0f,
- strokeLineCap = Butt, strokeLineJoin = Miter, strokeLineMiter = 4.0f,
- pathFillType = NonZero) {
- moveTo(13.44f, 12.96f)
- arcToRelative(0.96f, 0.96f, 0.0f, false, false, -0.96f, 0.96f)
- verticalLineToRelative(6.301f)
- curveToRelative(0.0f, 0.53f, 0.43f, 0.96f, 0.96f, 0.96f)
- horizontalLineToRelative(0.96f)
- arcToRelative(0.24f, 0.24f, 0.0f, false, true, 0.24f, 0.24f)
- verticalLineToRelative(2.039f)
- arcToRelative(0.24f, 0.24f, 0.0f, false, false, 0.4f, 0.178f)
- lineToRelative(2.446f, -2.21f)
- arcToRelative(0.96f, 0.96f, 0.0f, false, true, 0.643f, -0.247f)
- horizontalLineToRelative(4.43f)
- curveToRelative(0.531f, 0.0f, 0.96f, -0.43f, 0.96f, -0.96f)
- verticalLineTo(13.92f)
- arcToRelative(0.96f, 0.96f, 0.0f, false, false, -0.96f, -0.96f)
- horizontalLineToRelative(-9.12f)
- close()
- }
- }
- .build()
- return _thread!!
- }
-
-private var _thread: ImageVector? = null
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/GenericLoadingScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/GenericLoadingScreen.kt
deleted file mode 100644
index f31f16b..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/GenericLoadingScreen.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package uninit.genesis.app.ui.screens
-
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.size
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.core.screen.Screen
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import kotlinx.coroutines.launch
-import org.jetbrains.compose.resources.ExperimentalResourceApi
-import org.jetbrains.compose.resources.painterResource
-import org.koin.compose.getKoin
-import org.koin.core.Koin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.ui.components.Centered
-
-open class GenericLoadingScreen(
- val loadingText: String,
- val loadingProcedure: suspend (koin: Koin) -> Screen
-) : Screen {
- @OptIn(ExperimentalResourceApi::class)
- @Composable
- override fun Content() {
- val koin = getKoin()
- val prefs = koin.get()
- val dataStore = koin.get()
- val useDiscordIcon by prefs.preference("ui.discordIcon", false)
- Centered {
- if (dataStore.shiggyEasterEgg) {
- Image(
- painterResource("images/shiggy.gif"), // TODO: gif support :(
- contentDescription = "Shiggy",
- modifier = Modifier.size(100.dp)
- )
- Text("Shiggy")
- } else {
- Image(
- painterResource(if (useDiscordIcon) "images/img_logo.png" else "icons/genesis.png"),
- contentDescription = "${if (useDiscordIcon) "Discord" else "Genesis"} Logo",
- modifier = Modifier.size(100.dp)
- )
- Text(loadingText)
- }
- }
- val nav = LocalNavigator.currentOrThrow
-
- rememberCoroutineScope().launch {
- val screen = loadingProcedure(koin)
- nav.replace(screen)
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/RootScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/RootScreen.kt
deleted file mode 100644
index 4966844..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/RootScreen.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-package uninit.genesis.app.ui.screens
-
-import io.github.aakira.napier.Napier
-import uninit.common.fytix.Err
-import uninit.common.fytix.Ok
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.client.enum.LogLevel
-import uninit.genesis.app.ui.screens.auth.LoginScreen
-import uninit.genesis.app.ui.screens.client.GatewayLoadScreen
-import uninit.genesisApi.GenesisApiClient
-import uninit.genesisApi.types.update.UpdateRequest
-
-
-class RootScreen : GenericLoadingScreen(loadingText = "Welcome to Genesis", { koin ->
- val prefs = koin.get()
- val genesisApi = koin.get()
- val genesisClient = koin.get()
- var apiUUID by prefs.preference("api.uuid", "")
- try {
- val response = genesisApi.getUpdate(UpdateRequest(apiUUID, "0.0.0b", emptyMap()))
- val data = response.getOrNull()
- if (data != null) {
- apiUUID = data.uuid
- if (data.updateAvailable) {
- if (genesisClient.logLevel >= LogLevel.INFO) Napier.i(
- "Update available",
- null,
- "Genesis Api"
- )
- }
- if (data.pluginUpdates.isNotEmpty()) {
- if (genesisClient.logLevel >= LogLevel.INFO) Napier.i(
- "${data.pluginUpdates.size} plugin updates available",
- null,
- "Genesis Api"
- )
- }
- }
- } catch (e: Exception) {
- if (genesisClient.logLevel >= LogLevel.ERROR) Napier.e(
- "Error checking for updates",
- e,
- "Genesis Api"
- )
- }
-
-
- val token by prefs.preference("auth.token", "")
-
- if (token.isNotEmpty()) {
- when (val result = genesisClient.tryTokenLogin(token)) {
- is Ok -> {
- Napier.d(
- "Logged in as ${result.value.username}",
- null,
- "Client::LOGIN"
- )
- GatewayLoadScreen()
- }
-
- is Err -> {
- Napier.w(
- "Failed to login with token: ${result.error.message}",
- null,
- "Client::LOGIN"
- )
- LoginScreen()
- }
- }
- } else {
- Napier.d(
- "No token found",
- null,
- "Client::LOGIN"
- )
- LoginScreen()
- }
-})
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/auth/LoginScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/auth/LoginScreen.kt
deleted file mode 100644
index d349cf5..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/auth/LoginScreen.kt
+++ /dev/null
@@ -1,95 +0,0 @@
-package uninit.genesis.app.ui.screens.auth
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.rememberCoroutineScope
-import cafe.adriel.voyager.core.screen.Screen
-import cafe.adriel.voyager.core.screen.ScreenKey
-import cafe.adriel.voyager.core.screen.uniqueScreenKey
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import io.github.aakira.napier.Napier
-import kotlinx.coroutines.DelicateCoroutinesApi
-import kotlinx.coroutines.launch
-import org.koin.compose.getKoin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.client.enum.LogLevel
-import uninit.genesis.app.ui.components.Centered
-import uninit.genesis.app.ui.components.form.composeForm
-import uninit.genesis.app.ui.screens.client.GatewayLoadScreen
-
-class LoginScreen(
-
-) : Screen {
-
- override val key: ScreenKey = uniqueScreenKey
-
- @OptIn(DelicateCoroutinesApi::class)
- @Composable
- override fun Content() {
- val koin = getKoin()
- val prefs = koin.get()
- val genesisClient = koin.get()
- val navigator = LocalNavigator.currentOrThrow
-
- val scope = rememberCoroutineScope()
-
- var tokenPref by prefs.preference("auth.token", "")
-
- Centered {
- composeForm {
- /*
- twoSided {
- left("password") {
- head("Login")
- text("login", "Login")
- password("password", "Password")
- submit("Login")
- swap("Use token")
- }
- right("token") {
- head("Login with token")
- password("token", "Token")
- submit("Login with token")
- swap("Use password")
- }
- }
- */
- text("login", "Login")
- password("password", "Password")
- separator("separator", "Or, login with")
- password("token", "Token")
- switch("use-token", "Use token")
- separator("separator", "")
- switch("remember", "Remember me")
- assignSubmitText("Login")
- onSubmit {
- val formResponse = this
- scope.launch {
- if (formResponse["use-token"] as Boolean) {
- val token = formResponse["token"] as String
- genesisClient.rest.token = token
- val res = genesisClient.rest.getDomainMe()
- if (res.isOk()) {
- tokenPref = token
- if (genesisClient.logLevel >= LogLevel.INFO) Napier.i(
- "Logged in as ${res.getOrNull()!!.username}",
- null,
- "Login"
- )
- navigator.replace(GatewayLoadScreen())
- } else {
- genesisClient.rest.token = ""
- if (genesisClient.logLevel >= LogLevel.ERROR) Napier.e(
- "Invalid token",
- Throwable(res.errorOrNull()?.message),
- "Login"
- )
- }
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/ClientRootScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/ClientRootScreen.kt
deleted file mode 100644
index 6d21329..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/ClientRootScreen.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package uninit.genesis.app.ui.screens.client
-
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.slideInVertically
-import androidx.compose.animation.slideOutVertically
-import androidx.compose.material3.Icon
-import androidx.compose.material3.NavigationBar
-import androidx.compose.material3.NavigationBarItem
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import cafe.adriel.voyager.core.screen.Screen
-import cafe.adriel.voyager.navigator.tab.CurrentTab
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabNavigator
-import org.koin.compose.getKoin
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.ui.screens.client.messaging.GuildsTab
-import uninit.genesis.app.ui.screens.client.settings.SettingsTab
-
-enum class ClientTab(val tab: Tab) {
- GUILDS(GuildsTab),
- SETTINGS(SettingsTab)
-}
-
-class ClientRootScreen : Screen {
- @Composable
- override fun Content() {
- val koin = getKoin()
- val dataStore = koin.get()
-
- TabNavigator(ClientTab.values().first().tab) { tabNavigator ->
- dataStore.onClientTabSelect {
- tabNavigator.current = it.tab
- }
- Scaffold(
- content = {
- CurrentTab()
- },
- bottomBar = {
- AnimatedVisibility(
- visible = dataStore.mobileUi,
- // slide in from bottom
- enter = slideInVertically(initialOffsetY = { it }),
- exit = slideOutVertically(targetOffsetY = { it })
- ) {
- NavigationBar {
- ClientTab.values().map { it.tab }.forEach {
- NavigationBarItem(
- selected = tabNavigator.current == it,
- onClick = { tabNavigator.current = it },
- icon = {
- it.options.icon?.let { it1 ->
- Icon(
- painter = it1,
- contentDescription = it.options.title
- )
- }
- },
- label = {
- it.options.title.let { it1 -> Text(it1) }
- }
- )
-
- }
- }
- }
- }
- )
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/GatewayLoadScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/GatewayLoadScreen.kt
deleted file mode 100644
index bbc45cc..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/GatewayLoadScreen.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package uninit.genesis.app.ui.screens.client
-
-
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.app.ui.screens.GenericLoadingScreen
-
-class GatewayLoadScreen : GenericLoadingScreen(loadingText = "Welcome to Genesis", { koin ->
- val prefs = koin.get()
- val genesisClient = koin.get()
-
- val token by prefs.preference("auth.token", "")
-
- genesisClient.gateway.token = token
- genesisClient.gateway.connect()
-
- genesisClient.waitFor("READY")
-
-
-
- ClientRootScreen()
-})
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/ChannelsScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/ChannelsScreen.kt
deleted file mode 100644
index f571439..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/ChannelsScreen.kt
+++ /dev/null
@@ -1,298 +0,0 @@
-package uninit.genesis.app.ui.screens.client.messaging
-
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.slideInVertically
-import androidx.compose.animation.slideOutVertically
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material3.Button
-import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.core.screen.Screen
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import io.github.aakira.napier.Napier
-import io.kamel.core.ExperimentalKamelApi
-import io.kamel.image.KamelImage
-import io.kamel.image.KamelImageBox
-import org.jetbrains.compose.resources.ExperimentalResourceApi
-import org.jetbrains.compose.resources.painterResource
-import org.koin.compose.getKoin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.api.types.Snowflake
-import uninit.genesis.discord.api.types.timestamp
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.client.entities.guild.Channel
-import uninit.genesis.discord.client.entities.guild.Guild
-import uninit.genesis.discord.client.enum.LogLevel
-import uninit.genesis.discord.entities.guild.ChannelType
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.ui.components.User.Avatar
-import uninit.genesis.app.ui.components.icons.Icons
-import uninit.genesis.app.ui.components.icons.icons.Textchannel
-import uninit.genesis.app.ui.screens.client.ClientTab
-
-@OptIn(ExperimentalResourceApi::class)
-@Composable
-fun Channel(channel: Channel, select: (Channel) -> Unit) {
- var modifier = Modifier
- .clickable {
- select(channel)
- }
-
- val icon = when (channel.type) {
- ChannelType.GUILD_TEXT -> Icons.Textchannel
- else -> null
- }
-
- Row {
- if (icon != null) {
- Icon(
- imageVector = icon,
- contentDescription = null,
- modifier = modifier.padding(start = 8.dp, end = 4.dp)
- )
- } else if (channel.type == ChannelType.DM) {
- Avatar(channel.recipients.first())
- } else if (channel.type == ChannelType.GROUP_DM) {
- Box(
- modifier = Modifier
- .width(32.dp)
- .height(32.dp)
- .clip(shape = CircleShape)
- ) {
- if (channel.icon != null) {
- KamelImage(
- resource = channel.icon!!.render(
- 128
- ),
- contentDescription = channel.name,
- )
- } else {
- Image(
- painter = painterResource("images/defaults/group_dm_icon_${channel.id.timestamp % 8}.png"),
- contentDescription = channel.name,
- )
- }
- }
- } else modifier = modifier.padding(start = 12.dp)
- Text(
- channel.name, modifier =
- modifier
- )
- }
-}
-
-
-@Composable
-fun Category(
- category: Channel?, children: List, select: (Channel) -> Unit
-) {
- if (category != null) {
- Text(category.name,
- modifier = Modifier.clickable {
- category.isCollapsed.value = !category.isCollapsed.value
- })
- }
- if (category?.isCollapsed?.value != true) {
- children.forEach { channel ->
- Channel(channel) {
- select(it)
- }
- }
- }
-}
-
-class ChannelsScreen(
- private var _guild: Guild?,
- private val lastGuild: Snowflake
-) : Screen {
- @OptIn(ExperimentalResourceApi::class, ExperimentalKamelApi::class)
- @Composable
- override fun Content() {
- val koin = getKoin()
- val genesisClient = koin.get()
- val prefs = koin.get()
- val dataStore = koin.get()
- val navigator = LocalNavigator.currentOrThrow
-
- if (_guild == null) {
- if (genesisClient.logLevel >= LogLevel.ERROR) Napier.e(
- "Invalid guild",
- null,
- "Channels Screen"
- )
- navigator.replace(ChannelsScreen(genesisClient.guilds[lastGuild]!!, lastGuild))
- return
- }
-
- val guild = _guild!!
-
- val firstChannel = when (guild.id) {
- 0L -> guild.channels.first().id
- else -> guild.channels.find { it.type == ChannelType.GUILD_TEXT }!!.id
- }
-
- var currentChannel by prefs.preference(
- "client.currentChannel",
- firstChannel
- )
-
- if (guild.channels.find { it.id == currentChannel } == null) currentChannel = firstChannel
-
-
- var lastChannel by remember {
- mutableStateOf(currentChannel)
- }
-
- dataStore.compositionOnGuildSelect {
- navigator.push(ChannelsScreen(genesisClient.guilds[it]!!, guild.id))
- }
-
-
- Scaffold(
- modifier = Modifier
- .width(
- 200.dp
- ),
- bottomBar = {
- AnimatedVisibility(
- visible = !dataStore.mobileUi,
- // slide in from bottom
- enter = slideInVertically(initialOffsetY = { it }),
- exit = slideOutVertically(targetOffsetY = { it })
- ) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .height(48.dp)
- .background(color = MaterialTheme.colorScheme.primary)
- ) {
- val modifier = Modifier.align(Alignment.CenterVertically)
- Avatar(genesisClient.normalUser, modifier = modifier)
- Text(
- genesisClient.normalUser.displayName,
- modifier = modifier.width(100.dp),
- fontSize = MaterialTheme.typography.labelMedium.fontSize
- )
- Button(
- onClick = {
- dataStore.selectClientTab(ClientTab.SETTINGS)
-
- }
- ) {
- Text("Settings")
- }
- }
- }
- }
- ) {
- LazyColumn(
- modifier = Modifier
- .fillMaxWidth()
- .fillMaxHeight()
- .padding(bottom = 48.dp)
- ) {
-
- val uncategorized = mutableMapOf()
- val categories = mutableMapOf()
-
- guild.channels.forEach {
- if (it.type == ChannelType.GUILD_CATEGORY) {
- categories[it.id] = it
- }
- }
- guild.channels.forEach {
- if (it.type != ChannelType.GUILD_CATEGORY) {
- if (it.parentId != null) {
- if (categories[it.parentId!!]?.children?.contains(it.id) == true) {
- return@forEach
- }
- categories[it.parentId!!]!!.children.add(it.id)
- } else {
- uncategorized[it.id] = it
- }
- }
- }
-
- val sortedCategories = categories.values.sortedBy { it.position }
- val sortedUncategorized = uncategorized.values.sortedBy { it.position }
- val iterator = sortedCategories.iterator()
- while (iterator.hasNext()) {
- val category = iterator.next()
- category.children =
- category.children.sortedBy { guild.channels.find { it2 -> it2.id == it }!!.position }
- .toMutableList()
- }
-
-
- item {
- val modifier = Modifier
- .fillMaxWidth()
- .height(48.dp)
- if (guild.banner != null) {
- KamelImageBox(
- resource = guild.banner!!.render(480),
- modifier = modifier,
- onFailure = {
- Text(guild.name)
- }
- )
- {
- Text(guild.name)
- }
- }
- }
-
-
-
- if (sortedUncategorized.isNotEmpty())
- item {
- Category(null, sortedUncategorized) {
- lastChannel = currentChannel
- currentChannel = it.id
- dataStore.selectChannel(it.id)
- }
- }
-
- items(
- items = sortedCategories,
- key = { it.id }
- ) { category ->
- val children = category.children.map { channelId ->
- guild.channels.find { it2 -> it2.id == channelId }!!
- }
- Category(category, children) {
- lastChannel = currentChannel
- currentChannel = it.id
- dataStore.selectChannel(it.id)
- }
- }
-
- }
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/ChatScreen.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/ChatScreen.kt
deleted file mode 100644
index 733aeae..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/ChatScreen.kt
+++ /dev/null
@@ -1,245 +0,0 @@
-package uninit.genesis.app.ui.screens.client.messaging
-
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.material3.Button
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextField
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.key
-import androidx.compose.ui.input.key.onKeyEvent
-import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.core.screen.Screen
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import io.github.aakira.napier.Napier
-import kotlinx.coroutines.launch
-import org.koin.compose.getKoin
-import uninit.genesis.discord.api.types.Snowflake
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.client.entities.guild.Channel
-import uninit.genesis.discord.client.enum.LogLevel
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.ui.components.guild.message
-
-// Should be replaced with indexing
-@Suppress()
-class ChatScreen(
- private var _channel: Channel?,
- private var lastChannel: Snowflake
-) : Screen {
- @OptIn(ExperimentalFoundationApi::class)
- @Composable
- override fun Content() {
- val koin = getKoin()
- val genesisClient = koin.get()
- val dataStore = koin.get()
- val navigator = LocalNavigator.currentOrThrow
- val scope = rememberCoroutineScope()
-
- if (_channel == null) {
- if (genesisClient.logLevel >= LogLevel.ERROR) Napier.e(
- "Invalid channel",
- null,
- "Chat Screen"
- )
- navigator.replace(ChatScreen(genesisClient.channels[lastChannel]!!, lastChannel))
- return
- }
-
- val channel = _channel!!
-
-
- val listState = rememberLazyListState()
-
-
- var numNewMessages by remember { mutableStateOf(0) }
-
- fun scrollToBottom(animated: Boolean = false) {
- if (channel.messages.isEmpty()) return
- scope.launch {
- try {
- if (animated) listState.animateScrollToItem(channel.messages.size - 1)
- else listState.scrollToItem(channel.messages.size - 1)
- } catch (_: Exception) {
- }
- }
- }
-
- var showMemberList by remember { mutableStateOf(false) }
-
- fun newMessage(isBulk: Boolean = false) {
- val isAtBottom = !listState.canScrollForward
- if (isAtBottom) scrollToBottom()
- else if (!isBulk) numNewMessages++
- }
-
- if (channel.messages.isNotEmpty()) {
- scrollToBottom()
- } else {
- scope.launch {
- channel.fetchMessages(50)
- }
- }
-
- dataStore.compositionOnChannelSelect {
- navigator.push(
- ChatScreen(genesisClient.channels[it], channel.id)
- )
- }
- channel.compositionOnMessageCreate { newMessage() }
- channel.compositionOnMessageCreateBulk { newMessage(true) }
-
-
- var writtenMessage by remember { mutableStateOf("") }
- fun send() {
- val message = writtenMessage
- writtenMessage = ""
- scope.launch {
- channel.sendMessage(message)
- newMessage()
- }
- }
-
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .fillMaxHeight()
- ) {
-
- Scaffold(
- topBar = {
- val showNewMessages by remember {
- derivedStateOf {
- if (!listState.canScrollForward) numNewMessages = 0
- listState.canScrollForward && numNewMessages > 0
- }
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .height(48.dp)
- .background(color = MaterialTheme.colorScheme.primary),
- horizontalArrangement = Arrangement.SpaceBetween
- ) {
- AnimatedVisibility(visible = dataStore.mobileUi) {
- Button(
- onClick = {
- dataStore.toggleGuilds()
- },
- modifier = Modifier.align(alignment = Alignment.CenterVertically)
- ) {
- Text("Show Guilds")
- }
- }
- Box(
- modifier = Modifier.align(alignment = Alignment.CenterVertically)
- ) {
- Text(channel.name)
- }
- Button(
- onClick = {
- showMemberList = !showMemberList
- },
- modifier = Modifier.align(alignment = androidx.compose.ui.Alignment.CenterVertically)
- ) {
- Text("Members")
- }
- }
-
- if (showNewMessages) {
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .height(48.dp)
- .padding(top = 48.dp)
- .clickable {
- numNewMessages = 0
- scrollToBottom(true)
- }
- .background(color = MaterialTheme.colorScheme.primary)
- ) {
- Text("$numNewMessages new messages")
- }
- }
- },
- bottomBar = {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .height(48.dp)
- ) {
- TextField(
- value = writtenMessage,
- onValueChange = {
- writtenMessage = it
- },
- singleLine = true,
- modifier = Modifier.onKeyEvent {
- if (it.key == Key.Enter) {
- send()
- true
- } else {
- false
- }
- }
-
- )
- Button(onClick = {
- send()
- }) {
- Text("Send")
- }
- }
- }
- ) {
- LazyColumn(
- modifier = Modifier
- .fillMaxWidth()
- .padding(
- bottom = 48.dp
- ),
- state = listState,
- ) {
-
- items(
- items = channel.messages,
- key = { it.id }
- ) {
- message(it)
- }
- }
- }
- }
- AnimatedVisibility(visible = showMemberList) {
- MemberList(channel)
- }
- }
-
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/GuildsTab.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/GuildsTab.kt
deleted file mode 100644
index 62dc8ab..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/GuildsTab.kt
+++ /dev/null
@@ -1,290 +0,0 @@
-package uninit.genesis.app.ui.screens.client.messaging
-
-
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.offset
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.ExperimentalMaterialApi
-import androidx.compose.material.FractionalThreshold
-import androidx.compose.material.rememberSwipeableState
-import androidx.compose.material.swipeable
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.navigator.Navigator
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabOptions
-import io.kamel.image.KamelImage
-import kotlinx.coroutines.launch
-import org.jetbrains.compose.resources.ExperimentalResourceApi
-import org.jetbrains.compose.resources.painterResource
-import org.koin.compose.getKoin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.api.domain.user.GuildFolder
-import uninit.genesis.discord.api.types.Snowflake
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.entities.guild.ChannelType
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.ui.components.icons.Icons
-import uninit.genesis.app.ui.components.icons.icons.Empty
-import kotlin.math.roundToInt
-
-enum class GuildIconType {
- DM, GUILD, FOLDER
-}
-
-internal object GuildsTab : Tab {
-
- override val options: TabOptions
- @Composable
- get() {
- val icon = rememberVectorPainter(Icons.Empty)
- return remember {
- TabOptions(
- index = 0u,
- title = "Chat",
- icon = icon
- )
- }
- }
-
- @OptIn(
- ExperimentalResourceApi::class, ExperimentalFoundationApi::class,
- ExperimentalMaterialApi::class
- )
- @Composable
- override fun Content() {
- val koin = getKoin()
- val genesisClient = koin.get()
-
- val prefs = koin.get()
-
- var currentGuild by prefs.preference(
- "client.currentGuild",
- genesisClient.guilds.values.first()!!.id
- )
- val useDiscordIcon by prefs.preference("ui.discordIcon", false)
- var lastGuild by remember { mutableStateOf(genesisClient.guilds.values.find { it?.id != 0L }!!.id) }
- val dataStore = koin.get()
-
- val scope = rememberCoroutineScope()
- val swipeableState = rememberSwipeableState(0)
-
- dataStore.compositionOnToggleGuilds {
- scope.launch {
- if (swipeableState.currentValue == 0) swipeableState.animateTo(1)
- else swipeableState.animateTo(0)
- }
- }
-
-
- fun chooseGuild(id: Snowflake) {
- lastGuild = currentGuild
- currentGuild = id
- dataStore.selectGuild(id)
- val guild = genesisClient.guilds[id]!!
- dataStore.selectChannel(
- when (id) {
- 0L -> guild.channels.first().id
- else -> guild.channels.first { it.type == ChannelType.GUILD_TEXT }.id
- }
- )
- }
-
- val width = 500.dp
-
- Box(
- modifier = Modifier.swipeable(
- state = swipeableState,
- anchors = mapOf(0f to 0, width.value to 1),
- thresholds = { _, _ -> FractionalThreshold(0.3f) },
- orientation = Orientation.Horizontal
- )
- ) {
-
- Row {
- var rerenderBool by remember { mutableStateOf(true) }
- fun rerender() {
- rerenderBool = false
- }
- if (rerenderBool) {
- LazyColumn(
- modifier = Modifier
- .fillMaxHeight()
- .width(64.dp)
- ) {
- item(key = "DMS") {
- val modifier = Modifier
- .size(
- 48.dp,
- 48.dp
- )
- .clickable {
- chooseGuild(0L)
- }
-
- Box(
- modifier = if (currentGuild.toInt() == 0) {
- modifier.clip(RoundedCornerShape(2.dp))
- } else {
- modifier.clip(CircleShape)
- }
- ) {
- Image(
- painterResource(if (useDiscordIcon) "images/img_logo.png" else "icons/genesis.png"),
- contentDescription = "DMs",
- modifier = Modifier
- .size(24.dp)
- .align(Alignment.Center)
- )
- }
- }
-
- val notHitGuilds = genesisClient.guilds.keys.toMutableList()
- notHitGuilds.remove(0L)
- genesisClient.userSettings!!.guildFolders.forEach { folder ->
- folder.guildIds.forEach { guildId ->
- notHitGuilds.remove(guildId.toLong())
- }
- }
-
- if (notHitGuilds.size > 0) {
- genesisClient.userSettings!!.guildFolders.add(
- GuildFolder(
- id = null,
- name = "Other",
- color = null,
- guildIds = notHitGuilds.map { it.toString() },
- collapsed = false
- )
- )
- }
-
-
-
- items(
- items = genesisClient.userSettings!!.guildFolders,
- key = { it.id ?: it.guildIds.first() }
- ) { sortedFolder ->
- if (sortedFolder.guildIds.isEmpty()) return@items
- if (sortedFolder.guildIds.size == 1) {
- sortedFolder.collapsed = false
- } else {
- Box(
- modifier = Modifier
- .size(
- 48.dp,
- 48.dp
- )
- .clickable {
- sortedFolder.collapsed = !sortedFolder.collapsed
- rerender()
- }
- ) {
- Image(
- painter = painterResource("images/folder.png"),
- contentDescription = sortedFolder.name,
- colorFilter = ColorFilter.tint(
- Color(
- sortedFolder.color ?: 0x5865f2
- ).copy(alpha = 0.5f)
- ),
- modifier = Modifier
- .size(24.dp)
- .align(Alignment.Center)
- )
- }
-
- }
- if (!sortedFolder.collapsed) {
- sortedFolder.guildIds.forEach forEach2@{ guildId ->
- val guild = genesisClient.guilds[guildId.toLong()]
- if (guild === null) return@forEach2
- val modifier = Modifier
- .size(
- 48.dp,
- 48.dp
- )
- .clickable {
- chooseGuild(guildId.toLong())
- }
-
- Box(
- modifier = if (currentGuild == guildId.toLong()) {
- modifier.clip(RoundedCornerShape(2.dp))
- } else {
- modifier.clip(CircleShape)
- }
- ) {
- if (guild.icon !== null) KamelImage(
- resource = guild.icon!!.render(128),
- contentDescription = guild.name
- ) else {
- var str = ""
- guild.name.split(" ").forEach { word ->
- str += word[0]
- }
-
- Text(str)
- }
- }
- }
- }
- }
- }
- } else rerenderBool = true
- Navigator(ChannelsScreen(genesisClient.guilds[currentGuild], lastGuild))
- }
- val guild = genesisClient.guilds[currentGuild]!!
-
- val firstChannel = when (currentGuild) {
- 0L -> guild.channels.first().id
- else -> guild.channels.find { it.type == ChannelType.GUILD_TEXT }!!.id
- }
-
- var currentChannel by prefs.preference(
- "client.currentChannel",
- firstChannel
- )
-
- if (guild.channels.find { it.id == currentChannel } == null) currentChannel =
- firstChannel
-
-
- Box(
- modifier = Modifier.offset {
- IntOffset(
- if (dataStore.mobileUi) swipeableState.offset.value.roundToInt() else width.value.roundToInt(),
- 0
- )
- }
- ) {
- Navigator(ChatScreen(genesisClient.channels[currentChannel], currentChannel))
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/MemberList.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/MemberList.kt
deleted file mode 100644
index 2c2f0cc..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/messaging/MemberList.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package uninit.genesis.app.ui.screens.client.messaging
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.width
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import uninit.genesis.discord.client.entities.guild.Channel
-
-@Composable
-fun MemberList(channel: Channel) {
- Scaffold(
- modifier = Modifier.fillMaxHeight()
- .width(200.dp)
- .background(MaterialTheme.colorScheme.surface)
- ) {
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/SettingsTab.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/SettingsTab.kt
deleted file mode 100644
index e2c1ecb..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/SettingsTab.kt
+++ /dev/null
@@ -1,118 +0,0 @@
-package uninit.genesis.app.ui.screens.client.settings
-
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.Settings
-import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.navigator.tab.CurrentTab
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabNavigator
-import cafe.adriel.voyager.navigator.tab.TabOptions
-import org.koin.compose.getKoin
-import uninit.genesis.app.data.DataStore
-import uninit.genesis.app.ui.components.BackArrow
-import uninit.genesis.app.ui.screens.client.ClientTab
-import uninit.genesis.app.ui.screens.client.settings.pages.AccountSettings
-import uninit.genesis.app.ui.screens.client.settings.pages.AppearanceSettings
-import uninit.genesis.app.ui.screens.client.settings.pages.DevSettings
-import uninit.genesis.app.ui.screens.client.settings.pages.GenesisSettings
-
-enum class SettingPage(val tab: Tab) {
- ACCOUNT(AccountSettings),
- APPEARANCE(AppearanceSettings),
- GENESIS(GenesisSettings),
- DEV(DevSettings)
-}
-
-internal object SettingsTab : Tab {
- override val options: TabOptions
- @Composable
- get() {
- val icon = rememberVectorPainter(Icons.Outlined.Settings)
- return remember {
- TabOptions(
- index = 0u,
- title = "Settings",
- icon = icon
- )
- }
- }
-
- @Composable
- override fun Content() {
- val koin = getKoin()
- val dataStore = koin.get()
-
- var isSettingOpen by remember { mutableStateOf(false) }
- Box {
- if (!dataStore.mobileUi || isSettingOpen) {
- BackArrow(onClick = {
- if (dataStore.mobileUi) {
- isSettingOpen = false
- } else {
- dataStore.selectClientTab(ClientTab.GUILDS)
- }
- })
- }
- TabNavigator(SettingPage.values().first().tab) { tabNavigator ->
- Box(modifier = Modifier.padding(48.dp)) {
- Row {
-
- AnimatedVisibility(visible = !isSettingOpen || !dataStore.mobileUi) {
- LazyColumn(
- modifier = Modifier
- .padding(16.dp)
- ) {
- items(items = SettingPage.values().map { it.tab }) {
- Row(
- modifier = Modifier
- .clickable {
- tabNavigator.current = it
- if (dataStore.mobileUi) isSettingOpen = true
- }
- ) {
- it.options.icon?.let { it1 ->
- Icon(
- painter = it1,
- contentDescription = it.options.title
- )
- }
- Text(it.options.title)
- }
- }
- }
- }
- if (isSettingOpen || !dataStore.mobileUi) {
- Scaffold(
- content = {
- CurrentTab()
- },
- modifier = Modifier.background(MaterialTheme.colorScheme.onSurface),
- )
- }
- }
- }
- }
-
- }
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Account.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Account.kt
deleted file mode 100644
index adda461..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Account.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package uninit.genesis.app.ui.screens.client.settings.pages
-
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabOptions
-import org.koin.compose.getKoin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.app.ReloadClient
-import uninit.genesis.app.ui.components.User.Avatar
-import uninit.genesis.app.ui.components.icons.Icons
-import uninit.genesis.app.ui.components.icons.icons.Empty
-
-internal object AccountSettings : Tab {
- override val options: TabOptions
- @Composable
- get() {
- val icon = rememberVectorPainter(Icons.Empty)
- return remember {
- TabOptions(
- index = 0u,
- title = "Account",
- icon = icon
- )
- }
- }
-
- @Composable
- override fun Content() {
- val koin = getKoin()
- val genesisClient = koin.get()
- val prefs = koin.get()
- var tokenPref by prefs.preference("auth.token", "")
- val navigator = LocalNavigator.currentOrThrow
- LazyColumn {
- item {
- Row {
- Avatar(genesisClient.normalUser)
- Text(genesisClient.normalUser.displayName)
- }
- }
- item {
- Button(onClick = {
- tokenPref = ""
- ReloadClient(koin, navigator)
- }) {
- Text("Log Out")
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Appearance.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Appearance.kt
deleted file mode 100644
index 54ff666..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Appearance.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package uninit.genesis.app.ui.screens.client.settings.pages
-
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.Switch
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabOptions
-import org.koin.compose.getKoin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.app.ui.components.icons.Icons
-import uninit.genesis.app.ui.components.icons.icons.Empty
-
-internal object AppearanceSettings : Tab {
- override val options: TabOptions
- @Composable
- get() {
- val icon = rememberVectorPainter(Icons.Empty)
- return remember {
- TabOptions(
- index = 0u,
- title = "Appearance",
- icon = icon
- )
- }
- }
-
- @Composable
- override fun Content() {
- val koin = getKoin()
- val prefs = koin.get()
- var discordIcon by prefs.preference("ui.discordIcon", false)
- LazyColumn {
-
- item {
- Row {
- Text("Use Discord Icon")
- Switch(
- checked = discordIcon,
- onCheckedChange = {
- discordIcon = it
- }
- )
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Dev.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Dev.kt
deleted file mode 100644
index 28d79ca..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Dev.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-package uninit.genesis.app.ui.screens.client.settings.pages
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.DropdownMenu
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabOptions
-import org.koin.compose.getKoin
-import uninit.common.compose.preferences.PreferencesManager
-import uninit.genesis.app.ui.components.icons.Icons
-import uninit.genesis.app.ui.components.icons.icons.Empty
-import uninit.genesis.discord.client.GenesisClient
-import uninit.genesis.discord.client.enum.LogLevel
-
-internal object DevSettings : Tab {
- override val options: TabOptions
- @Composable
- get() {
- val icon = rememberVectorPainter(Icons.Empty)
- return remember {
- TabOptions(
- index = 0u,
- title = "Developer",
- icon = icon
- )
- }
- }
-
- @Composable
- override fun Content() {
- val koin = getKoin()
- val prefs = koin.get()
- val genesisClient = koin.get()
- var logLevel by prefs.preference("debug.logLevel", LogLevel.INFO.name)
- LazyColumn {
-
- item {
- Row {
- var logLevelShown by remember { mutableStateOf(false) }
- Box(
- modifier = Modifier.clickable {
- logLevelShown = !logLevelShown
- }
- .width(100.dp)
- .height(50.dp)
- .background(MaterialTheme.colorScheme.surface)
- ) {
- Text(logLevel)
- }
-
- DropdownMenu(
- expanded = logLevelShown,
- onDismissRequest = { /*TODO*/ },
- modifier = Modifier.width(100.dp)
- ) {
- LogLevel.values().forEach { level ->
- DropdownMenuItem(
- text = { Text(level.name) },
- onClick = {
- logLevelShown = false
- logLevel = level.name
- genesisClient.logLevel = level
- }
- )
- }
- }
- }
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Genesis.kt b/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Genesis.kt
deleted file mode 100644
index dc3ead0..0000000
--- a/genesis/app/src/commonMain/kotlin/xyz/genesisapp/genesis/app/ui/screens/client/settings/pages/Genesis.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package uninit.genesis.app.ui.screens.client.settings.pages
-
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.Button
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.graphics.vector.rememberVectorPainter
-import cafe.adriel.voyager.navigator.LocalNavigator
-import cafe.adriel.voyager.navigator.currentOrThrow
-import cafe.adriel.voyager.navigator.tab.Tab
-import cafe.adriel.voyager.navigator.tab.TabOptions
-import org.koin.compose.getKoin
-import uninit.genesis.app.ReloadClient
-import uninit.genesis.app.ui.components.icons.Icons
-import uninit.genesis.app.ui.components.icons.icons.Empty
-
-internal object GenesisSettings : Tab {
- override val options: TabOptions
- @Composable
- get() {
- val icon = rememberVectorPainter(Icons.Empty)
- return remember {
- TabOptions(
- index = 0u,
- title = "Genesis",
- icon = icon
- )
- }
- }
-
- @Composable
- override fun Content() {
- val koin = getKoin()
- val navigator = LocalNavigator.currentOrThrow
- LazyColumn {
-
- item {
- Button(onClick = {
- ReloadClient(koin, navigator)
- }) {
- Text("Reload")
- }
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/desktopMain/kotlin/uninit/genesis/app/KoinModules.desktop.kt b/genesis/app/src/desktopMain/kotlin/uninit/genesis/app/KoinModules.desktop.kt
new file mode 100644
index 0000000..0b59598
--- /dev/null
+++ b/genesis/app/src/desktopMain/kotlin/uninit/genesis/app/KoinModules.desktop.kt
@@ -0,0 +1,18 @@
+package uninit.genesis.app
+
+import io.ktor.client.engine.*
+import io.ktor.client.engine.okhttp.*
+import org.koin.core.module.Module
+import org.koin.dsl.module
+import uninit.common.compose.preferences.PreferencesManager
+import androidx.compose.runtime.Composable
+
+@Composable
+actual fun platformNativeModuleImpl() = module {
+ single {
+ PreferencesManager(".genesis.json")
+ }
+ single {
+ OkHttp
+ }
+}
\ No newline at end of file
diff --git a/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/Logger.kt b/genesis/app/src/desktopMain/kotlin/uninit/genesis/app/Logger.kt
similarity index 100%
rename from genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/Logger.kt
rename to genesis/app/src/desktopMain/kotlin/uninit/genesis/app/Logger.kt
diff --git a/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/main.desktop.kt b/genesis/app/src/desktopMain/kotlin/uninit/genesis/app/main.desktop.kt
similarity index 100%
rename from genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/main.desktop.kt
rename to genesis/app/src/desktopMain/kotlin/uninit/genesis/app/main.desktop.kt
diff --git a/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.desktop.kt b/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.desktop.kt
deleted file mode 100644
index 2c0a12c..0000000
--- a/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.desktop.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package uninit.genesis.app.di
-
-import io.ktor.client.engine.*
-import io.ktor.client.engine.okhttp.*
-
-actual val platformHttpEngineFactory: HttpClientEngineFactory<*> = OkHttp
\ No newline at end of file
diff --git a/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.desktop.kt b/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.desktop.kt
deleted file mode 100644
index 4fc7a4b..0000000
--- a/genesis/app/src/desktopMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.desktop.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package uninit.genesis.app.di
-
-import androidx.compose.runtime.Composable
-import org.koin.core.module.Module
-import org.koin.dsl.module
-import uninit.common.compose.preferences.PreferencesManager
-
-@Composable
-actual fun preferencesModule(): Module {
- return module {
- single {
- PreferencesManager(".genesis.json")
- }
- }
-}
\ No newline at end of file
diff --git a/genesis/app/src/iosMain/kotlin/uninit/genesis/app/KoinModules.ios.kt b/genesis/app/src/iosMain/kotlin/uninit/genesis/app/KoinModules.ios.kt
new file mode 100644
index 0000000..71c91fd
--- /dev/null
+++ b/genesis/app/src/iosMain/kotlin/uninit/genesis/app/KoinModules.ios.kt
@@ -0,0 +1,12 @@
+package uninit.genesis.app
+
+import org.koin.dsl.module
+import uninit.common.compose.preferences.PreferencesManager
+import androidx.compose.runtime.Composable
+
+@Composable
+actual fun platformNativeModuleImpl() = module {
+ single {
+ PreferencesManager()
+ }
+}
\ No newline at end of file
diff --git a/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/main.ios.kt b/genesis/app/src/iosMain/kotlin/uninit/genesis/app/main.ios.kt
similarity index 100%
rename from genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/main.ios.kt
rename to genesis/app/src/iosMain/kotlin/uninit/genesis/app/main.ios.kt
diff --git a/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.ios.kt b/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.ios.kt
deleted file mode 100644
index c20ca09..0000000
--- a/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/di/httpModule.ios.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package uninit.genesis.app.di
-
-import io.ktor.client.engine.*
-import io.ktor.client.engine.darwin.*
-
-actual val platformHttpEngineFactory: HttpClientEngineFactory<*> = Darwin
\ No newline at end of file
diff --git a/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.ios.kt b/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.ios.kt
deleted file mode 100644
index 623d87d..0000000
--- a/genesis/app/src/iosMain/kotlin/xyz/genesisapp/genesis/app/di/preferencesModule.ios.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package uninit.genesis.app.di
-
-import androidx.compose.runtime.Composable
-import org.koin.core.module.Module
-import org.koin.dsl.module
-import uninit.common.compose.preferences.PreferencesManager
-
-@Composable
-
-actual fun preferencesModule(): Module {
- return module {
- single { PreferencesManager() }
- }
-}
\ No newline at end of file
diff --git a/genesis/discord/client/build.gradle.kts b/genesis/discord/client/build.gradle.kts
index 5726bfd..9dc9412 100644
--- a/genesis/discord/client/build.gradle.kts
+++ b/genesis/discord/client/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
kotlin("multiplatform")
id("com.android.library")
- id("org.jetbrains.compose")
+// id("org.jetbrains.compose")
alias(libs.plugins.kotlinx.serialization)
`maven-publish`
}
@@ -26,10 +26,10 @@ kotlin {
implementation(libs.ktor.client.websockets)
implementation(libs.ktor.client.logging)
implementation(libs.ktor.serialization.json)
- compileOnly(compose.runtime)
- compileOnly(compose.foundation)
+ compileOnly(libs.compose.runtime)
+ compileOnly(libs.compose.foundation)
- compileOnly(libs.kamel)
+// compileOnly(libs.kamel)
compileOnly(libs.koin.core)
compileOnly(libs.koin.compose)
@@ -38,8 +38,8 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation(project(":genesis:discord:api"))
- implementation(libs.uninit.common)
- implementation(libs.uninit.common.compose)
+ implementation(project(":uninit:common"))
+ implementation(project(":uninit:common-compose"))
}
diff --git a/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/Asset.kt b/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/Asset.kt
index 5a515a4..89d8a5d 100644
--- a/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/Asset.kt
+++ b/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/Asset.kt
@@ -2,9 +2,6 @@ package uninit.genesis.discord.client.entities
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter
-import io.kamel.core.Resource
-import io.kamel.core.isSuccess
-import io.kamel.image.asyncPainterResource
import uninit.genesis.discord.api.types.Asset
import uninit.genesis.discord.api.types.AssetType
import uninit.genesis.discord.api.types.Snowflake
@@ -16,7 +13,7 @@ class Asset(
val type: AssetType,
val parentId: Snowflake? = null,
) {
- private val sizeCache: MutableMap> = mutableMapOf()
+ private val sizeCache: MutableMap = mutableMapOf()
fun toUrl(extension: String = "png", size: Int? = null): String {
@@ -38,11 +35,11 @@ class Asset(
return builder.toString()
}
- @Composable
- fun render(size: Int, extension: String = "png"): Resource {
- if (!sizeCache.keys.contains(size) || !sizeCache[size]!!.isSuccess) {
- sizeCache[size] = asyncPainterResource(toUrl(extension, size))
- }
- return sizeCache[size]!!
- }
+// @Composable
+// fun render(size: Int, extension: String = "png"): Resource {
+// if (!sizeCache.keys.contains(size) || !sizeCache[size]!!.isSuccess) {
+// sizeCache[size] = asyncPainterResource(toUrl(extension, size))
+// }
+// return sizeCache[size]!!
+// }
}
\ No newline at end of file
diff --git a/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/guild/Channel.kt b/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/guild/Channel.kt
index 29e987f..37504af 100644
--- a/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/guild/Channel.kt
+++ b/genesis/discord/client/src/commonMain/kotlin/xyz/genesisapp/discord/client/entities/guild/Channel.kt
@@ -68,9 +68,9 @@ class Channel(
/**
* Explicit typing for [compositionLocalOn] function, event is [List]
*/
- @Composable
- fun compositionOnMessageCreateBulk(block: Event>.(List) -> Unit) =
- compositionLocalOn("MESSAGE_CREATE_BULK", block)
+// @Composable
+// fun compositionOnMessageCreateBulk(block: Event>.(List) -> Unit) =
+// compositionLocalOn("MESSAGE_CREATE_BULK", block)
/**
* Explicit typing for [emit] function, event is [Snowflake]
@@ -85,9 +85,9 @@ class Channel(
/**
* Explicit typing for [compositionLocalOn] function, event is [Snowflake]
*/
- @Composable
- fun compositionOnMessageDelete(block: Event.(Snowflake) -> Unit) =
- compositionLocalOn("MESSAGE_DELETE", block)
+// @Composable
+// fun compositionOnMessageDelete(block: Event.(Snowflake) -> Unit) =
+// compositionLocalOn("MESSAGE_DELETE", block)
private fun addMessage(message: Message, isBulk: Boolean = false): Message {
diff --git a/genesis/genesisApi/build.gradle.kts b/genesis/genesisApi/build.gradle.kts
index 4dfb8f8..f3b0c49 100644
--- a/genesis/genesisApi/build.gradle.kts
+++ b/genesis/genesisApi/build.gradle.kts
@@ -25,7 +25,7 @@ kotlin {
implementation(libs.ktor.serialization.json)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
- implementation(libs.uninit.common)
+ implementation(project(":uninit:common"))
}
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 375bb3a..86e81f0 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,21 +1,23 @@
[versions]
uninit = "0.0.1-20231130-7d823d9"
-kotlin = "1.9.20"
-serialization = "1.6.1"
+kotlin = "2.0.0"
+serialization = "1.7.0-RC"
android = "8.1.2"
-compose = "1.5.10"
-moko-resources = "0.23.0"
-koin = "3.5.2-RC1"
-koin-compose = "1.1.1-RC1"
-voyager = "1.0.0-rc10"
-ktor = "2.3.6"
-napier = "2.6.1"
+koin = "3.6.0-alpha1"
+koin-compose = "3.6.0-alpha1"
+voyager = "1.1.0-beta01"
+ktor = "2.3.11"
+napier = "2.7.1"
gson = "2.10.1"
kprefs = "0.12.1"
-kamel = "0.8.2"
+#kamel = "v1.0.0-beta.5"
+kotlinx = "1.8.1"
+compose = "1.6.10"
[libraries]
+kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx" }
+
uninit-common = { group = "uninit", name = "common", version.ref = "uninit" }
uninit-common-compose = { group = "uninit", name = "common-compose", version.ref = "uninit" }
@@ -23,10 +25,6 @@ serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serializ
serialization-protobuf = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-protobuf", version.ref = "serialization" }
serialization-preferences = { group = "net.edwardday.serialization", name = "kprefs", version.ref = "kprefs" }
-moko-resources-common = { group = "dev.icerock.moko", name = "resources", version.ref = "moko-resources" }
-moko-resources-compose = { group = "dev.icerock.moko", name = "resources-compose", version.ref = "moko-resources" }
-moko-resources-generator = { group = "dev.icerock.moko", name = "resources-generator", version.ref = "moko-resources" }
-
koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" }
koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" }
koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koin-compose" }
@@ -50,16 +48,35 @@ ktor-serialization-json = { group = "io.ktor", name = "ktor-serialization-kotlin
napier = { group = "io.github.aakira", name = "napier", version.ref = "napier" }
-kamel = { group = "media.kamel", name = "kamel-image", version.ref = "kamel" }
+#kamel = { group = "media.kamel", name = "kamel-image", version.ref = "kamel" }
+
+compose-animation = { group = "org.jetbrains.compose.animation", name = "animation", version.ref = "compose" }
+compose-animation-graphics = { group = "org.jetbrains.compose.animation", name = "animation-graphics", version.ref = "compose" }
+compose-foundation = { group = "org.jetbrains.compose.foundation", name = "foundation", version.ref = "compose" }
+compose-material = { group = "org.jetbrains.compose.material", name = "material", version.ref = "compose" }
+compose-material3 = { group = "org.jetbrains.compose.material3", name = "material3", version.ref = "compose" }
+compose-runtime = { group = "org.jetbrains.compose.runtime", name = "runtime", version.ref = "compose" }
+compose-ui = { group = "org.jetbrains.compose.ui", name = "ui", version.ref = "compose" }
+
+compose-desktop-common = { group = "org.jetbrains.compose.desktop", name = "desktop", version.ref = "compose" }
+compose-desktop-jvm-linux-x64 = { group = "org.jetbrains.compose.desktop", name = "desktop-jvm-linux-x64", version.ref = "compose" }
+compose-desktop-jvm-macos-x64 = { group = "org.jetbrains.compose.desktop", name = "desktop-jvm-macos-x64", version.ref = "compose" }
+compose-desktop-jvm-windows-x64 = { group = "org.jetbrains.compose.desktop", name = "desktop-jvm-windows-x64", version.ref = "compose" }
+compose-desktop-jvm-linux-arm64 = { group = "org.jetbrains.compose.desktop", name = "desktop-jvm-linux-arm64", version.ref = "compose" }
+compose-desktop-jvm-macos-arm64 = { group = "org.jetbrains.compose.desktop", name = "desktop-jvm-macos-arm64", version.ref = "compose" }
+
+compose-components-resources = { group = "org.jetbrains.compose.components", name = "components-resources", version.ref = "compose" }
+
+
[plugins]
android-application = { id = "com.android.application", version.ref = "android" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
-kotlin-compose = { id = "org.jetbrains.compose", version.ref = "compose" }
+kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+kotlin-compose-plugin = { id = "org.jetbrains.compose", version.ref = "compose" }
android-library = { id = "com.android.library", version.ref = "android" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
-moko-resources-multiplatform = { id = "dev.icerock.mobile.multiplatform-resources", version.ref = "moko-resources" }
[bundles]
diff --git a/settings.gradle.kts b/settings.gradle.kts
index cbed322..082b3d2 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,4 +1,4 @@
-rootProject.name = "uninit"
+rootProject.name = "uninit-genesis"
pluginManagement {
repositories {
google()
@@ -33,3 +33,5 @@ include(":genesis:common")
include(":genesis:genesisApi")
// include(":genesis:nativeVoice") TODO: soon:tm:
+include(":uninit:common")
+include(":uninit:common-compose")
diff --git a/uninit/build.gradle.kts b/uninit/build.gradle.kts
new file mode 100644
index 0000000..e69de29
diff --git a/uninit/common-compose/build.gradle.kts b/uninit/common-compose/build.gradle.kts
new file mode 100644
index 0000000..dfe0342
--- /dev/null
+++ b/uninit/common-compose/build.gradle.kts
@@ -0,0 +1,80 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.multiplatform)
+ alias(libs.plugins.kotlin.compose.compiler)
+ alias(libs.plugins.kotlinx.serialization)
+ `maven-publish`
+}
+
+kotlin {
+ androidTarget {
+ publishLibraryVariants("release")
+ }
+ jvm("desktop")
+ iosArm64().binaries.framework {
+ baseName = "uninitCommonCompose"
+ }
+
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(libs.serialization.json)
+ implementation(libs.kotlinx.coroutines.core)
+
+ compileOnly(libs.compose.runtime)
+ compileOnly(libs.compose.foundation)
+
+ compileOnly(libs.ktor.client.core)
+ compileOnly(libs.ktor.client.negotiation)
+
+ // These have to be implementation or else gradle will pitch a fit
+ implementation(libs.koin.core)
+ implementation(libs.koin.compose)
+
+ implementation(project(":uninit:common"))
+
+ }
+ resources.srcDirs("resources")
+ }
+
+ val androidMain by getting {}
+ val desktopMain by getting {
+ dependencies {
+ implementation(libs.jvm.gson)
+ }
+ }
+ }
+}
+
+android {
+ compileSdk = (findProperty("android.compileSdk") as String).toInt()
+ namespace = "uninit.common.compose"
+
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+ sourceSets["main"].res.srcDirs("src/androidMain/res")
+ sourceSets["main"].resources.srcDirs("src/commonMain/resources")
+
+ defaultConfig {
+ minSdk = (findProperty("android.minSdk") as String).toInt()
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlin {
+ jvmToolchain(17)
+ }
+}
+publishing {
+ @Suppress("UNCHECKED_CAST")
+ (extra["maven-repository"] as (PublishingExtension.() -> Unit)?)?.invoke(this)
+
+ publications {
+ create("uninit.common.compose") {
+ groupId = "uninit"
+ artifactId = "common-compose"
+ version = project.version.toString()
+ from(components["kotlin"])
+ }
+ }
+}
diff --git a/uninit/common-compose/src/androidMain/AndroidManifest.xml b/uninit/common-compose/src/androidMain/AndroidManifest.xml
new file mode 100644
index 0000000..568741e
--- /dev/null
+++ b/uninit/common-compose/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/platform/LocalApplicationContext.kt b/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/platform/LocalApplicationContext.kt
new file mode 100644
index 0000000..ff2a738
--- /dev/null
+++ b/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/platform/LocalApplicationContext.kt
@@ -0,0 +1,7 @@
+package uninit.common.compose.platform
+
+import android.content.Context
+import androidx.compose.runtime.compositionLocalOf
+
+@Suppress("USELESS_CAST")
+val LocalApplicationContext = compositionLocalOf { null as Context? }
\ No newline at end of file
diff --git a/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.android.kt b/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.android.kt
new file mode 100644
index 0000000..1c03bb4
--- /dev/null
+++ b/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.android.kt
@@ -0,0 +1,105 @@
+package uninit.common.compose.preferences
+
+import android.content.SharedPreferences
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.serializer
+import uninit.common.compose.preferences.Preference
+import uninit.common.compose.preferences.SerializablePreferenceApi
+import kotlin.reflect.KClass
+
+/**
+ * PlatformPreferencesManager is a multiplatform (Android, iOS, Desktop) preferences manager
+ * that aims to provide a simple, consistent API for storing and retrieving preferences
+ * of many types, including serializable objects.
+ *
+ * On desktop, this is implemented using a JSON file in a platform-specific config folder.
+ * This file also supports object nesting (a key at `a.b.c` will be stored in the JSON
+ * as `{"a": {"b": {"c": "value"}}}`).
+ *
+ * On Windows, this is `%APPDATA%/Genesis/genesis.json`
+ *
+ * On Linux and macOS, this is `~/.config/genesis/genesis.json`
+ *
+ * On Android, this is implemented using SharedPreferences. Serializable objects are
+ * stored as JSON strings.
+ *
+ * On iOS, this is implemented using NSUserDefaults. Serializable objects are stored
+ * as JSON strings.
+ *
+ *
+ * ### Serializable data storage
+ *
+ * Serialized data, when taken as a (key: String, value: T) pair, is stored as a string value
+ * in the platform preferences. setter and getter functions are required to provide reified
+ * type information for serialization and deserialization as well as runtime type checking.
+ *
+ * For serialized data types, the key will be stored as "key#${T::class.simpleName}" and the
+ * value will be stored as a JSON string.
+ * @see [Preference]
+ */
+
+@Suppress("NAME_SHADOWING")
+actual class PlatformPreferencesManager(val prefs: SharedPreferences) : SerializablePreferenceApi() {
+ override fun preference(key: String, defaultValue: String): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getString(key, defaultValue) ?: defaultValue
+ }, { value ->
+ prefs.edit().putString(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Int): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getInt(key, defaultValue)
+ }, { value ->
+ prefs.edit().putInt(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Long): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getLong(key, defaultValue)
+ }, { value ->
+ prefs.edit().putLong(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Float): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getFloat(key, defaultValue)
+ }, { value ->
+ prefs.edit().putFloat(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Boolean): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getBoolean(key, defaultValue)
+ }, { value ->
+ prefs.edit().putBoolean(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Set): Preference> {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getStringSet(key, defaultValue) ?: defaultValue
+ }, { value ->
+ prefs.edit().putStringSet(key, value).apply()
+ })
+ }
+
+ @OptIn(InternalSerializationApi::class)
+ override fun preference(key: String, defaultValue: T, klass: KClass): Preference {
+ return Preference("$key#[${klass.simpleName}]", defaultValue, { key, defaultValue ->
+ val json = prefs.getString(key, null)
+ if (json == null) {
+ defaultValue
+ } else {
+ Json.decodeFromString(klass.serializer(), json)
+ }
+ }, { value ->
+ prefs.edit().putString(key, Json.encodeToString(klass.serializer(), value)).apply()
+ })
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt b/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt
new file mode 100644
index 0000000..b632543
--- /dev/null
+++ b/uninit/common-compose/src/androidMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt
@@ -0,0 +1,56 @@
+package uninit.common.compose.preferences
+
+import android.content.SharedPreferences
+import uninit.common.compose.preferences.Preference
+import uninit.common.compose.preferences.PreferenceApi
+
+@Suppress("NAME_SHADOWING")
+actual class PreferencesManager(val prefs: SharedPreferences) : PreferenceApi() {
+ override fun preference(key: String, defaultValue: String): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getString(key, defaultValue) ?: defaultValue
+ }, { value ->
+ prefs.edit().putString(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Int): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getInt(key, defaultValue)
+ }, { value ->
+ prefs.edit().putInt(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Long): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getLong(key, defaultValue)
+ }, { value ->
+ prefs.edit().putLong(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Float): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getFloat(key, defaultValue)
+ }, { value ->
+ prefs.edit().putFloat(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Boolean): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getBoolean(key, defaultValue)
+ }, { value ->
+ prefs.edit().putBoolean(key, value).apply()
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Set): Preference> {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ prefs.getStringSet(key, defaultValue) ?: defaultValue
+ }, { value ->
+ prefs.edit().putStringSet(key, value).apply()
+ })
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/fytix/ComposableEventBus.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/fytix/ComposableEventBus.kt
new file mode 100644
index 0000000..54d938e
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/fytix/ComposableEventBus.kt
@@ -0,0 +1,28 @@
+package uninit.common.compose.fytix
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import uninit.common.fytix.EventBus
+
+@Suppress("UNCHECKED_CAST")
+open class ComposableEventBus(val composableId: String = ""): EventBus() {
+
+ @Composable
+ fun compositionLocalOn(event: String, func: Event.(E) -> Unit) {
+ val listener = object : EventListener> {
+ override val uuid: Int = latestUuid++
+ override fun onEvent(event: Event) = event.func(event.data)
+ } as EventListener>
+ DisposableEffect("EventBus#{{$composableId}}+${listener.uuid}") {
+ if (busses.containsKey(event)) {
+ busses[event]!!.add(listener)
+ } else {
+ busses[event] = mutableListOf(listener)
+ }
+ byId[listener.uuid] = listener
+ onDispose {
+ off(listener.uuid)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/inverse.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/inverse.kt
new file mode 100644
index 0000000..69c682c
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/inverse.kt
@@ -0,0 +1,27 @@
+package uninit.common.compose
+
+import androidx.compose.runtime.MutableState
+
+
+fun MutableState.inverse(): MutableState {
+ val primary = this
+
+ return object : MutableState {
+ override var value: Boolean
+ get() = component1()
+ set(value) {
+ component2().invoke(value)
+ }
+
+ override fun component1(): Boolean {
+ return !primary.value
+ }
+
+ override fun component2(): (Boolean) -> Unit {
+ return { value ->
+ primary.component2()(!value)
+ }
+ }
+
+ }
+}
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/koin/Module.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/koin/Module.kt
new file mode 100644
index 0000000..009adce
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/koin/Module.kt
@@ -0,0 +1,10 @@
+package uninit.common.compose.koin
+
+import io.ktor.client.engine.HttpClientEngineFactory
+import org.koin.dsl.module
+
+fun uninitModule(
+ httpFactory: HttpClientEngineFactory<*>
+) = module {
+ single { httpModule(httpFactory) }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/koin/http.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/koin/http.kt
new file mode 100644
index 0000000..b69d201
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/koin/http.kt
@@ -0,0 +1,16 @@
+package uninit.common.compose.koin
+
+import androidx.compose.runtime.Composable
+import io.ktor.client.HttpClient
+import io.ktor.client.engine.HttpClientEngineFactory
+import org.koin.compose.getKoin
+import org.koin.core.qualifier.named
+import org.koin.dsl.module
+
+
+internal fun httpModule(factory: HttpClientEngineFactory<*>) = module {
+ single(named("uninitCommonComposeHttp")) { HttpClient(factory) }
+}
+
+@Composable
+internal fun getHttpClient() = getKoin().get(named("uninitCommonComposeHttp"))
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/MultiplatformPreferencesManager.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/MultiplatformPreferencesManager.kt
new file mode 100644
index 0000000..4eaa197
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/MultiplatformPreferencesManager.kt
@@ -0,0 +1,5 @@
+package uninit.common.compose.preferences
+
+
+
+expect class PreferencesManager : PreferenceApi
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.kt
new file mode 100644
index 0000000..a8133c4
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.kt
@@ -0,0 +1,34 @@
+package uninit.common.compose.preferences
+
+
+/**
+ * PlatformPreferencesManager is a multiplatform (Android, iOS, Desktop) preferences manager
+ * that aims to provide a simple, consistent API for storing and retrieving preferences
+ * of many types, including serializable objects.
+ *
+ * On desktop, this is implemented using a JSON file in a platform-specific config folder.
+ * This file also supports object nesting (a key at `a.b.c` will be stored in the JSON
+ * as `{"a": {"b": {"c": "value"}}}`).
+ *
+ * On Windows, this is `%APPDATA%/Genesis/genesis.json`
+ *
+ * On Linux and macOS, this is `~/.config/genesis/genesis.json`
+ *
+ * On Android, this is implemented using SharedPreferences. Serializable objects are
+ * stored as JSON strings.
+ *
+ * On iOS, this is implemented using NSUserDefaults. Serializable objects are stored
+ * as JSON strings.
+ *
+ *
+ * ### Serializable data storage
+ *
+ * Serialized data, when taken as a (key: String, value: T) pair, is stored as a string value
+ * in the platform preferences. setter and getter functions are required to provide reified
+ * type information for serialization and deserialization as well as runtime type checking.
+ *
+ * For serialized data types, the key will be stored as "key#[${T::class.simpleName}]" and the
+ * value will be stored as a JSON string.
+ * @see [Preference]
+ */
+expect class PlatformPreferencesManager: SerializablePreferenceApi
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/Preference.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/Preference.kt
new file mode 100644
index 0000000..4c1026d
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/Preference.kt
@@ -0,0 +1,32 @@
+package uninit.common.compose.preferences
+
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+
+class Preference(
+ private val key: String,
+ private val defaultValue: T,
+ private val getter: (String, T) -> T,
+ private val setter: (T) -> Unit,
+ internal val state: MutableState = mutableStateOf(getter(key, defaultValue))
+) : MutableState by state {
+ override var value: T
+ get() = state.component1()
+ set(value) = component2().invoke(value)
+ override fun component1(): T {
+ return value
+ }
+ override fun component2(): (T) -> Unit {
+ return {
+ state.component2().invoke(it)
+ setter(it)
+ }
+ }
+
+ operator fun getValue(thisRef: Any?, property: Any?): T {
+ return value
+ }
+ operator fun setValue(thisRef: Any?, property: Any?, value: T) {
+ this.value = value
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/PreferenceApi.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/PreferenceApi.kt
new file mode 100644
index 0000000..71e5c06
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/PreferenceApi.kt
@@ -0,0 +1,34 @@
+package uninit.common.compose.preferences
+
+abstract class PreferenceApi {
+
+ abstract fun preference(
+ key: String,
+ defaultValue: String,
+ ): Preference
+
+ abstract fun preference(
+ key: String,
+ defaultValue: Int,
+ ): Preference
+
+ abstract fun preference(
+ key: String,
+ defaultValue: Long,
+ ): Preference
+
+ abstract fun preference(
+ key: String,
+ defaultValue: Float,
+ ): Preference
+
+ abstract fun preference(
+ key: String,
+ defaultValue: Boolean,
+ ): Preference
+
+ abstract fun preference(
+ key: String,
+ defaultValue: Set,
+ ): Preference>
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/SerializablePreferenceApi.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/SerializablePreferenceApi.kt
new file mode 100644
index 0000000..c72f845
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/SerializablePreferenceApi.kt
@@ -0,0 +1,11 @@
+package uninit.common.compose.preferences
+
+import kotlin.reflect.KClass
+
+abstract class SerializablePreferenceApi : PreferenceApi() {
+ abstract fun preference(
+ key: String,
+ defaultValue: T,
+ klass: KClass,
+ ): Preference
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/convertIDynValue.kt b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/convertIDynValue.kt
new file mode 100644
index 0000000..c501dee
--- /dev/null
+++ b/uninit/common-compose/src/commonMain/kotlin/uninit/common/compose/preferences/convertIDynValue.kt
@@ -0,0 +1,12 @@
+package uninit.common.compose.preferences
+
+import uninit.common.interfaces.IDynValue
+
+fun IDynValue.toPreference(key: String, defaultValue: T): Preference {
+ var t by this
+ return Preference(key, defaultValue, { _, _ ->
+ return@Preference t
+ }, { v ->
+ t = v
+ })
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.desktop.kt b/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.desktop.kt
new file mode 100644
index 0000000..951a5a5
--- /dev/null
+++ b/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.desktop.kt
@@ -0,0 +1,68 @@
+package uninit.common.compose.preferences
+
+import uninit.common.Platform
+import uninit.common.platform.OsFamily
+import uninit.common.serialization.GsonAdapter
+import kotlin.reflect.KClass
+
+/**
+ * PlatformPreferencesManager is a multiplatform (Android, iOS, Desktop) preferences manager
+ * that aims to provide a simple, consistent API for storing and retrieving preferences
+ * of many types, including serializable objects.
+ *
+ * On desktop, this is implemented using a JSON file in a platform-specific config folder.
+ * This file also supports object nesting (a key at `a.b.c` will be stored in the JSON
+ * as `{"a": {"b": {"c": "value"}}}`).
+ *
+ * On Windows, this is `%APPDATA%/Genesis/genesis.json`
+ *
+ * On Linux and macOS, this is `~/.config/genesis/genesis.json`
+ *
+ * On Android, this is implemented using SharedPreferences. Serializable objects are
+ * stored as JSON strings.
+ *
+ * On iOS, this is implemented using NSUserDefaults. Serializable objects are stored
+ * as JSON strings.
+ *
+ *
+ * ### Serializable data storage
+ *
+ * Serialized data, when taken as a (key: String, value: T) pair, is stored as a string value
+ * in the platform preferences. setter and getter functions are required to provide reified
+ * type information for serialization and deserialization as well as runtime type checking.
+ *
+ * For serialized data types, the key will be stored as "key#${T::class.simpleName}" and the
+ * value will be stored as a JSON string.
+ * @see [Preference]
+ */
+actual class PlatformPreferencesManager(prefsFile: String = platformPrefsFile()) : SerializablePreferenceApi() {
+ var prefs: GsonAdapter
+ init {
+ prefs = GsonAdapter(prefsFile)
+ }
+
+ override fun preference(key: String, defaultValue: String): Preference
+ = prefs.value(key, defaultValue).toPreference(key, defaultValue)
+ override fun preference(key: String, defaultValue: Int): Preference
+ = prefs.value(key, defaultValue).toPreference(key, defaultValue)
+ override fun preference(key: String, defaultValue: Long): Preference
+ = prefs.value(key, defaultValue).toPreference(key, defaultValue)
+ override fun preference(key: String, defaultValue: Float): Preference
+ = prefs.value(key, defaultValue).toPreference(key, defaultValue)
+ override fun preference(key: String, defaultValue: Boolean): Preference
+ = prefs.value(key, defaultValue).toPreference(key, defaultValue)
+ override fun preference(key: String, defaultValue: Set): Preference>
+ = prefs.value(key, defaultValue).toPreference(key, defaultValue)
+ override fun preference(key: String, defaultValue: T, klass: KClass): Preference
+ = prefs.value("${key}#[${klass.simpleName}]", defaultValue, klass).toPreference(key, defaultValue)
+ companion object {
+ private fun platformPrefsFile(): String {
+ return when (Platform.osFamily) {
+ OsFamily.WINDOWS -> System.getenv("APPDATA") + "/Genesis/genesis.json"
+ OsFamily.LINUX -> System.getProperty("user.home") + "/.config/genesis/genesis.json"
+ OsFamily.MACOS -> System.getProperty("user.home") + "/Library/Application Support/Genesis/genesis.json"
+ else -> throw Exception("Unsupported platform")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PrefUtils.kt b/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PrefUtils.kt
new file mode 100644
index 0000000..b96c92f
--- /dev/null
+++ b/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PrefUtils.kt
@@ -0,0 +1 @@
+package uninit.common.compose.preferences
diff --git a/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt b/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt
new file mode 100644
index 0000000..cd47d16
--- /dev/null
+++ b/uninit/common-compose/src/desktopMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt
@@ -0,0 +1,58 @@
+package uninit.common.compose.preferences
+
+import uninit.common.serialization.GsonAdapter
+
+actual class PreferencesManager(prefsFile: String) : PreferenceApi() {
+ var prefs: GsonAdapter
+ init {
+ prefs = GsonAdapter(prefsFile)
+ }
+ override fun preference(key: String, defaultValue: String): Preference {
+ var value by prefs.value(key, defaultValue)
+ return Preference(key, defaultValue, { _, _ ->
+ value
+ }, { v ->
+ value = v
+ })
+ }
+ override fun preference(key: String, defaultValue: Int): Preference {
+ var value by prefs.value(key, defaultValue)
+ return Preference(key, defaultValue, {_, _ ->
+ value
+ }, { v ->
+ value = v
+ })
+ }
+ override fun preference(key: String, defaultValue: Long): Preference {
+ var value by prefs.value(key, defaultValue)
+ return Preference(key, defaultValue, { _, _ ->
+ value
+ }, { v ->
+ value = v
+ })
+ }
+ override fun preference(key: String, defaultValue: Float): Preference {
+ var value by prefs.value(key, defaultValue)
+ return Preference(key, defaultValue, { _, _ ->
+ value
+ }, { v ->
+ value = v
+ })
+ }
+ override fun preference(key: String, defaultValue: Boolean): Preference {
+ var value by prefs.value(key, defaultValue)
+ return Preference(key, defaultValue, { _, _ ->
+ value
+ }, { v ->
+ value = v
+ })
+ }
+ override fun preference(key: String, defaultValue: Set): Preference> {
+ var value by prefs.value(key, defaultValue)
+ return Preference(key, defaultValue, { _, _ ->
+ value
+ }, { v ->
+ value = v
+ })
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/iosMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.ios.kt b/uninit/common-compose/src/iosMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.ios.kt
new file mode 100644
index 0000000..dec2af9
--- /dev/null
+++ b/uninit/common-compose/src/iosMain/kotlin/uninit/common/compose/preferences/PlatformPreferencesManager.ios.kt
@@ -0,0 +1,110 @@
+package uninit.common.compose.preferences
+
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.serializer
+import platform.Foundation.NSUserDefaults
+import kotlin.reflect.KClass
+
+/**
+ * PlatformPreferencesManager is a multiplatform (Android, iOS, Desktop) preferences manager
+ * that aims to provide a simple, consistent API for storing and retrieving preferences
+ * of many types, including serializable objects.
+ *
+ * On desktop, this is implemented using a JSON file in a platform-specific config folder.
+ * This file also supports object nesting (a key at `a.b.c` will be stored in the JSON
+ * as `{"a": {"b": {"c": "value"}}}`).
+ *
+ * On Windows, this is `%APPDATA%/Genesis/genesis.json`
+ *
+ * On Linux and macOS, this is `~/.config/genesis/genesis.json`
+ *
+ * On Android, this is implemented using SharedPreferences. Serializable objects are
+ * stored as JSON strings.
+ *
+ * On iOS, this is implemented using NSUserDefaults. Serializable objects are stored
+ * as JSON strings.
+ *
+ *
+ * ### Serializable data storage
+ *
+ * Serialized data, when taken as a (key: String, value: T) pair, is stored as a string value
+ * in the platform preferences. setter and getter functions are required to provide reified
+ * type information for serialization and deserialization as well as runtime type checking.
+ *
+ * For serialized data types, the key will be stored as "key#${T::class.simpleName}" and the
+ * value will be stored as a JSON string.
+ * @see [Preference]
+ */
+@Suppress("UNCHECKED_CAST", "NAME_SHADOWING", "USELESS_ELVIS")
+actual class PlatformPreferencesManager : SerializablePreferenceApi() {
+ @OptIn(InternalSerializationApi::class)
+ override fun preference(key: String, defaultValue: T, klass: KClass): Preference {
+ return Preference("$key#[${klass.simpleName}]", defaultValue, { key, defaultValue ->
+ val value = NSUserDefaults.standardUserDefaults.stringForKey(key)
+ when (value) {
+ null -> defaultValue
+ else -> Json.decodeFromString(klass.serializer(), value)
+ }
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setObject(Json.encodeToString(klass.serializer(), value), key)
+ })
+ }
+
+ override fun preference(key: String, defaultValue: String): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.stringForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setObject(value, key)
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Int): Preference {
+
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.integerForKey(key).toInt() ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setInteger(value.toLong(), key)
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Long): Preference {
+
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.integerForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setInteger(value, key)
+ })
+
+ }
+
+ override fun preference(key: String, defaultValue: Float): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.floatForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setFloat(value, key)
+ })
+ }
+
+ // elvis operator always returns
+ override fun preference(key: String, defaultValue: Boolean): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.boolForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setBool(value, key)
+ })
+ }
+
+ override fun preference(key: String, defaultValue: Set): Preference> {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ val value =
+ (NSUserDefaults.standardUserDefaults.stringArrayForKey(key) as List).toSet()
+ when (value.size) {
+ 0 -> defaultValue
+ else -> value
+ }
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setObject(value, key)
+ })
+ }
+}
\ No newline at end of file
diff --git a/uninit/common-compose/src/iosMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt b/uninit/common-compose/src/iosMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt
new file mode 100644
index 0000000..02c0c20
--- /dev/null
+++ b/uninit/common-compose/src/iosMain/kotlin/uninit/common/compose/preferences/PreferencesManager.kt
@@ -0,0 +1,68 @@
+package uninit.common.compose.preferences
+
+import platform.Foundation.NSUserDefaults
+
+actual class PreferencesManager : PreferenceApi() {
+ @Suppress("NAME_SHADOWING")
+ override fun preference(key: String, defaultValue: String): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.stringForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setObject(value, key)
+ })
+ }
+
+ @Suppress("NAME_SHADOWING", "USELESS_ELVIS")
+ override fun preference(key: String, defaultValue: Int): Preference {
+
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.integerForKey(key).toInt() ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setInteger(value.toLong(), key)
+ })
+ }
+
+ @Suppress("NAME_SHADOWING", "USELESS_ELVIS")
+ override fun preference(key: String, defaultValue: Long): Preference {
+
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.integerForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setInteger(value, key)
+ })
+
+ }
+
+ @Suppress("NAME_SHADOWING", "USELESS_ELVIS")
+ override fun preference(key: String, defaultValue: Float): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.floatForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setFloat(value, key)
+ })
+ }
+
+ // elvis operator always returns
+ @Suppress("NAME_SHADOWING", "USELESS_ELVIS")
+ override fun preference(key: String, defaultValue: Boolean): Preference {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ NSUserDefaults.standardUserDefaults.boolForKey(key) ?: defaultValue
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setBool(value, key)
+ })
+ }
+
+ @Suppress("UNCHECKED_CAST", "NAME_SHADOWING")
+ override fun preference(key: String, defaultValue: Set): Preference> {
+ return Preference(key, defaultValue, { key, defaultValue ->
+ val value =
+ (NSUserDefaults.standardUserDefaults.stringArrayForKey(key) as List).toSet()
+ when (value.size) {
+ 0 -> defaultValue
+ else -> value
+ }
+ }, { value ->
+ NSUserDefaults.standardUserDefaults.setObject(value, key)
+ })
+ }
+}
\ No newline at end of file
diff --git a/uninit/common/build.gradle.kts b/uninit/common/build.gradle.kts
new file mode 100644
index 0000000..3daa18f
--- /dev/null
+++ b/uninit/common/build.gradle.kts
@@ -0,0 +1,79 @@
+@Suppress("DSL_SCOPE_VIOLATION")
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.multiplatform)
+ alias(libs.plugins.kotlinx.serialization)
+ `maven-publish`
+}
+
+kotlin {
+
+ androidTarget {
+ publishLibraryVariants("release")
+ }
+ jvm("desktop")
+ iosArm64().binaries.framework {
+ baseName = "uninitCommon"
+ }
+
+ sourceSets {
+ val commonMain by getting {
+ dependencies {
+ implementation(libs.serialization.json)
+ implementation(libs.kotlinx.coroutines.core)
+ }
+ resources.srcDirs("resources")
+ }
+
+ val commonTest by getting {
+ dependencies {
+ implementation(kotlin("test"))
+ }
+ }
+
+ val androidMain by getting {}
+ val desktopMain by getting {
+ dependencies {
+ implementation(libs.jvm.gson)
+ }
+ }
+ }
+}
+
+android {
+ compileSdk = (findProperty("android.compileSdk") as String).toInt()
+ namespace = "uninit.common"
+
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+ sourceSets["main"].res.srcDirs("src/androidMain/res")
+ sourceSets["main"].resources.srcDirs("src/commonMain/resources")
+
+ defaultConfig {
+ minSdk = (findProperty("android.minSdk") as String).toInt()
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlin {
+ jvmToolchain(17)
+ }
+}
+
+publishing {
+ @Suppress("UNCHECKED_CAST")
+ (extra["maven-repository"] as (PublishingExtension.() -> Unit)?)?.invoke(this)
+
+ publications {
+ create("uninit.common") {
+ groupId = "uninit"
+ artifactId = "common"
+ version = project.version.toString()
+ from(components["kotlin"])
+ }
+ }
+}
+
+
+
+true
\ No newline at end of file
diff --git a/uninit/common/src/androidMain/AndroidManifest.xml b/uninit/common/src/androidMain/AndroidManifest.xml
new file mode 100644
index 0000000..568741e
--- /dev/null
+++ b/uninit/common/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/uninit/common/src/androidMain/kotlin/uninit/common/platform.android.kt b/uninit/common/src/androidMain/kotlin/uninit/common/platform.android.kt
new file mode 100644
index 0000000..949ac4b
--- /dev/null
+++ b/uninit/common/src/androidMain/kotlin/uninit/common/platform.android.kt
@@ -0,0 +1,13 @@
+package uninit.common
+
+import uninit.common.platform.OsFamily
+
+actual object Platform {
+ actual val osFamily: OsFamily
+ get() = OsFamily.ANDROID
+
+ actual fun vibrate(iosIntensity: Float, iosSharpness: Float, androidTime: Int) {
+ // TODO: This is a stub. Implement this method.
+ }
+
+}
\ No newline at end of file
diff --git a/uninit/common/src/androidMain/kotlin/uninit/common/platform.kt b/uninit/common/src/androidMain/kotlin/uninit/common/platform.kt
new file mode 100644
index 0000000..7aa4a23
--- /dev/null
+++ b/uninit/common/src/androidMain/kotlin/uninit/common/platform.kt
@@ -0,0 +1,3 @@
+package uninit.common
+
+actual fun getTimeInMillis(): Long = System.currentTimeMillis()
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/Getter.kt b/uninit/common/src/commonMain/kotlin/uninit/common/Getter.kt
new file mode 100644
index 0000000..97033ee
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/Getter.kt
@@ -0,0 +1,10 @@
+package uninit.common
+
+class Getter(val get: () -> T) {
+ operator fun getValue(thisRef: Any?, property: Any?): T {
+ return get()
+ }
+
+}
+
+fun getter(get: () -> T): Getter = Getter(get)
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/LinearGradient.kt b/uninit/common/src/commonMain/kotlin/uninit/common/LinearGradient.kt
new file mode 100644
index 0000000..890a916
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/LinearGradient.kt
@@ -0,0 +1,79 @@
+package uninit.common
+
+
+
+class LinearGradient(vararg colors: GradientStop) {
+ val colors: List
+ init {
+ if (colors.filter { it.stop != null }.map { it.stop }.distinct().size != colors.filter { it.stop != null }.size) {
+ throw IllegalArgumentException("Stops must be unique")
+ } else if (
+ colors.filter { it.stop != null }.map { it.stop }.any { it!! > 100 || it < 0 }
+ || colors.filter { it.stop != null }.let { it.isNotEmpty() && it.size != colors.size }
+ ) {
+ throw IllegalArgumentException("Stops must be between 0 and 100 and must be specified for all colors or none")
+ }
+ this.colors = colors.toList()
+
+ }
+
+ data class GradientStop(val rgba: RGBA, val stop: Float?)
+ data class RGBA(val r: Int, val g: Int, val b: Int, val a: Int) {
+ companion object {
+ val BLACK: RGBA
+ get() = RGBA(0, 0, 0, 255)
+ val WHITE: RGBA
+ get() = RGBA(255, 255, 255, 255)
+ }
+ }
+
+
+
+ operator fun get(index: Float): RGBA {
+ if (index < 0 || index > 100) {
+ throw IllegalArgumentException("Index must be between 0 and 100")
+ }
+ val stops = colors.filter { it.stop != null }
+ if (stops.filter {
+ if (it.stop == index) {
+ return@get it.rgba
+ } else {
+ return@filter false
+ }}.let { true } /* micro-optimization here, micro-optimization there */) {
+
+ val lastColor = stops.filter { it.stop!! < index }.maxByOrNull { it.stop!! }
+ val nextColor = stops.filter { it.stop!! > index }.minByOrNull { it.stop!! }
+
+ if (lastColor == null) {
+ return nextColor!!.rgba
+ } else if (nextColor == null) {
+ return lastColor.rgba
+ } else {
+ val lastColorIndex = lastColor.stop!!
+ val nextColorIndex = nextColor.stop!!
+ val lastColorRGBA = lastColor.rgba
+ val nextColorRGBA = nextColor.rgba
+ val percent = (index - lastColorIndex) / (nextColorIndex - lastColorIndex)
+ return RGBA(
+ (lastColorRGBA.r + (nextColorRGBA.r - lastColorRGBA.r) * percent).toInt(),
+ (lastColorRGBA.g + (nextColorRGBA.g - lastColorRGBA.g) * percent).toInt(),
+ (lastColorRGBA.b + (nextColorRGBA.b - lastColorRGBA.b) * percent).toInt(),
+ (lastColorRGBA.a + (nextColorRGBA.a - lastColorRGBA.a) * percent).toInt()
+ )
+ }
+
+ }
+ throw IllegalStateException("Unreachable.")
+ }
+}
+
+fun color(r: Int, g: Int, b: Int, a: Int = 255, stopPercent: Float? = null): LinearGradient.GradientStop {
+ return LinearGradient.GradientStop(LinearGradient.RGBA(r, g, b, a), stopPercent)
+}
+fun color(color: LinearGradient.RGBA, stopPercent: Float? = null): LinearGradient.GradientStop {
+ return LinearGradient.GradientStop(color, stopPercent)
+}
+
+fun linearGradient(vararg colors: LinearGradient.GradientStop): LinearGradient {
+ return LinearGradient(*colors)
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/Platform.kt b/uninit/common/src/commonMain/kotlin/uninit/common/Platform.kt
new file mode 100644
index 0000000..8bb3838
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/Platform.kt
@@ -0,0 +1,10 @@
+package uninit.common
+
+import uninit.common.platform.OsFamily
+
+expect object Platform {
+
+ val osFamily: OsFamily
+
+ fun vibrate(iosIntensity: Float, iosSharpness: Float, androidTime: Int)
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/Time.kt b/uninit/common/src/commonMain/kotlin/uninit/common/Time.kt
new file mode 100644
index 0000000..9b70507
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/Time.kt
@@ -0,0 +1,3 @@
+package uninit.common
+
+expect fun getTimeInMillis(): Long
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/fytix/EventBus.kt b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/EventBus.kt
new file mode 100644
index 0000000..f5fe39f
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/EventBus.kt
@@ -0,0 +1,107 @@
+package uninit.common.fytix
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+@Suppress("UNCHECKED_CAST")
+open class EventBus {
+
+ interface EventListener {
+ val uuid: Int
+ fun onEvent(event: E)
+ }
+
+ interface Event {
+ val type: String
+ val data: E
+ }
+
+ val busses: MutableMap>>> = mutableMapOf()
+
+ val byId: MutableMap>> = mutableMapOf()
+
+ var latestUuid: Int = 0
+
+ fun on(event: String, func: Event.(E) -> Unit) {
+ val listener = object : EventListener> {
+ override val uuid: Int = latestUuid++
+ override fun onEvent(event: Event) = event.func(event.data)
+ } as EventListener>
+ if (busses.containsKey(event)) {
+ busses[event]!!.add(listener)
+ } else {
+ busses[event] = mutableListOf(listener)
+ }
+ byId[listener.uuid] = listener
+ }
+
+ fun emit(event: String, data: A) {
+ if (!busses.containsKey(event)) return // TODO: Default ("UNKNOWN" event) event bus & "ALL" event
+ CoroutineScope((Dispatchers.Default)).launch {
+ val listeners = busses[event]!!
+ val iterator = listeners.iterator()
+ while (iterator.hasNext()) {
+ val listener = iterator.next()
+
+
+ withContext(Dispatchers.Default) {
+ listener.onEvent(object : Event {
+ override val type: String = event
+ override val data: A = data
+ })
+ }
+
+ }
+ }
+ }
+ fun directEmit(event: String, data: A) {
+ if (!busses.containsKey(event)) return // TODO: Default ("UNKNOWN" event) event bus & "ALL" event
+ val listeners = busses[event]!!
+ val iterator = listeners.iterator()
+ while (iterator.hasNext()) {
+ val listener = iterator.next()
+ listener.onEvent(object : Event {
+ override val type: String = event
+ override val data: A = data
+ })
+ }
+ }
+
+ fun once(event: String, func: Event.(E) -> Unit) {
+ val listener = object : EventListener> {
+ override val uuid: Int = latestUuid++
+ override fun onEvent(event: Event) {
+ event.func(event.data)
+ off(uuid)
+ }
+ } as EventListener>
+ if (busses.containsKey(event)) {
+ busses[event]!!.add(listener)
+ } else {
+ busses[event] = mutableListOf(listener)
+ }
+ byId[listener.uuid] = listener
+ }
+
+ suspend fun waitFor(event: String): E {
+ var result: E? = null
+ once(event) {
+ result = data
+ }
+ while (result == null) {
+ delay(1)
+ }
+ return result!!
+ }
+
+ fun off(uuid: Int) {
+ val listener = byId[uuid] ?: return
+ busses.values.indexOfFirst { it.remove(listener) }
+ byId.remove(uuid)
+ }
+
+
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/fytix/Option.kt b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/Option.kt
new file mode 100644
index 0000000..8541a52
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/Option.kt
@@ -0,0 +1,52 @@
+package uninit.common.fytix
+
+sealed class Option {
+ fun map(transform: (T) -> R): Option {
+ return when (this) {
+ is Some -> Some(transform(value))
+ is None -> None()
+ }
+ }
+
+ fun isSome(): Boolean {
+ return when (this) {
+ is Some -> true
+ is None -> false
+ }
+ }
+
+ fun isNone(): Boolean {
+ return when (this) {
+ is Some -> false
+ is None -> true
+ }
+ }
+
+ fun getOrNull(): T? {
+ return when (this) {
+ is Some -> value
+ is None -> null
+ }
+ }
+
+ fun unwrap(): T {
+ return when (this) {
+ is Some -> value
+ is None -> throw Exception("Option is None")
+ }
+ }
+}
+
+class Some(val value: T) : Option()
+class None : Option()
+
+fun option(block: () -> T?): Option {
+ return try {
+ when (val result = block()) {
+ null -> None()
+ else -> Some(result)
+ }
+ } catch (e: Exception) {
+ None()
+ }
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/fytix/README.md b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/README.md
new file mode 100644
index 0000000..b3d5609
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/README.md
@@ -0,0 +1,3 @@
+## what is fytix?
+
+fuck you this isnt {x}
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/fytix/Result.kt b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/Result.kt
new file mode 100644
index 0000000..4619b5c
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/fytix/Result.kt
@@ -0,0 +1,71 @@
+package uninit.common.fytix
+
+sealed class Result {
+ fun map(transform: (T) -> R): Result {
+ return when (this) {
+ is Ok -> Ok(transform(value))
+ is Err -> Err(error)
+ }
+ }
+
+ fun mapError(transform: (E) -> R): Result {
+ return when (this) {
+ is Ok -> Ok(value)
+ is Err -> Err(transform(error))
+ }
+ }
+
+ fun isOk(): Boolean {
+ return when (this) {
+ is Ok -> true
+ is Err -> false
+ }
+ }
+
+ fun isError(): Boolean {
+ return when (this) {
+ is Ok -> false
+ is Err -> true
+ }
+ }
+
+ fun getOrNull(): T? {
+ return when (this) {
+ is Ok -> value
+ is Err -> null
+ }
+ }
+
+ fun errorOrNull(): E? {
+ return when (this) {
+ is Ok -> null
+ is Err -> error
+ }
+ }
+
+ fun unwrap(): T {
+ return when (this) {
+ is Ok -> value
+ is Err -> throw Exception("Result is Err")
+ }
+ }
+
+ fun unwrapError(): E {
+ return when (this) {
+ is Ok -> throw Exception("Result is Ok")
+ is Err -> error
+ }
+ }
+}
+class Ok(val value: T) : Result()
+class Err(val error: E) : Result()
+
+fun result(block: () -> T): Result {
+ return try {
+ Ok(block())
+ } catch (e: Exception) {
+ Err(e)
+ }
+}
+
+
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/interfaces/IDynValue.kt b/uninit/common/src/commonMain/kotlin/uninit/common/interfaces/IDynValue.kt
new file mode 100644
index 0000000..1056bdd
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/interfaces/IDynValue.kt
@@ -0,0 +1,8 @@
+package uninit.common.interfaces
+
+import kotlin.reflect.KProperty
+
+interface IDynValue {
+ operator fun getValue(thisRef: Any?, property: KProperty<*>): T
+ operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T)
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/platform/OsFamily.kt b/uninit/common/src/commonMain/kotlin/uninit/common/platform/OsFamily.kt
new file mode 100644
index 0000000..c086f88
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/platform/OsFamily.kt
@@ -0,0 +1,9 @@
+package uninit.common.platform
+
+enum class OsFamily {
+ MACOS,
+ WINDOWS,
+ LINUX,
+ ANDROID,
+ IOS
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonMain/kotlin/uninit/common/serialization/JsonParser.kt b/uninit/common/src/commonMain/kotlin/uninit/common/serialization/JsonParser.kt
new file mode 100644
index 0000000..e75966c
--- /dev/null
+++ b/uninit/common/src/commonMain/kotlin/uninit/common/serialization/JsonParser.kt
@@ -0,0 +1,153 @@
+package uninit.common.serialization
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+
+/**
+ * "Ported" from [mewsic-common](https://github.com/mewsicapp/common/blob/meow/src/commonMain/kotlin/com/mewsic/common/processing/JsonParser.kt)
+ * This represents a parsed JSON object with no type information.
+ */
+class JsonParser {
+ @PublishedApi
+ internal val deserializer = Json {
+ ignoreUnknownKeys = true
+ }
+ val element: JsonElement
+
+ /**
+ * @constructor Creates a new JsonParser object from a [String].
+ * @param json The [String] to parse.
+ */
+
+ constructor(json: String) {
+ element = deserializer.parseToJsonElement(json)
+ }
+
+ /**
+ * @constructor Creates a new JsonParser object from a [JsonElement].
+ * @param element the [JsonElement] this parser represents.
+ */
+
+ constructor(json: JsonElement) {
+ element = json
+ }
+
+ /**
+ * Get the value of the given index.
+ * @param index The index of the value to get.
+ * @return The value of the given index.
+ * @throws IllegalArgumentException If the element is not a [JsonArray].
+ * @operator []
+ */
+ operator fun get(index: Int) : JsonParser? {
+ if (element !is JsonArray) {
+ throw IllegalArgumentException("Element is not a JsonArray")
+ }
+ if (element.jsonArray.size <= index) {
+ return null
+ }
+ return JsonParser(element.jsonArray[index])
+ }
+ /**
+ * Get the value of the given key.
+ * @param key The key of the value to get.
+ * @return The value of the given key.
+ * @throws IllegalArgumentException If the element is not a [JsonObject].
+ * @operator []
+ */
+ operator fun get(key: String) : JsonParser? {
+ return element.jsonObject[key]?.let { JsonParser(it) }
+ }
+
+ /**
+ * Check if the key is present in the element.
+ * @param key The key to check.
+ * @return True if the key is present, false otherwise.
+ * @throws IllegalArgumentException If the element is not a [JsonObject].
+ */
+ fun has(key: String) : Boolean {
+ return element.jsonObject.containsKey(key)
+ }
+
+ /**
+ * Interprets the element as any deserializable type.
+ * @param T The type to interpret the element as.
+ * @return The interpreted element.
+ * @throws SerializationException if the object cannot be decoded into T.
+ *
+ */
+ inline fun interpret() : T {
+ return deserializer.decodeFromJsonElement(element)
+ }
+
+ /**
+ * Interprets the element at the given key as any deserializable type.
+ * @param key The key of the element to interpret.
+ * @param T The type to interpret the element as.
+ * @return The interpreted element.
+ * @throws SerializationException if the object cannot be decoded into T.
+ */
+ inline fun get(key: String) : T {
+ return deserializer.decodeFromJsonElement(element.jsonObject[key]!!)
+ }
+
+ /**
+ * Takes in a string in the format of "key1.key2[3].key4" and returns a [JsonParser] that points to the value of the given key.
+ * @param path The path to the value to get.
+ * @return A [JsonParser] that points to the value of the given key.
+ * @throws IllegalArgumentException If the element that the path points to is not of valid type for the next step.
+ */
+ fun travel(path: String): JsonParser {
+ var current = this
+ for (key in path.split(".", "[", "]")) {
+ current = try {
+ current[key.toInt()]!!
+ } catch (e: NumberFormatException) {
+ current[key]!!
+ }
+ }
+ return current
+ }
+
+ /**
+ * Turns the element into a [List]
+ * @return A [List] that contains all the elements in the element.
+ * @throws IllegalArgumentException If the element is not a [JsonArray].
+ */
+ fun toList() : List {
+ return element.jsonArray.map { JsonParser(it) }
+ }
+
+ /**
+ * @return The element as a [String].
+ */
+ override fun toString(): String {
+ return element.toString()
+ }
+
+ /**
+ * The value of the element parsed as a [String].
+ */
+ val string: String
+ get() = interpret()
+ /**
+ * The value of the element parsed as an [Int].
+ */
+ val int: Int
+ get() = interpret()
+ /**
+ * The value of the element parsed as a [Long].
+ */
+ val long: Long
+ get() = interpret()
+ /**
+ * The value of the element parsed as a [Double].
+ */
+ val double: Double
+ get() = interpret()
+ /**
+ * The value of the element parsed as a [Boolean].
+ */
+ val bool: Boolean
+ get() = interpret()
+}
\ No newline at end of file
diff --git a/uninit/common/src/commonTest/kotlin/uninit/common/fytix/EventBusTests.kt b/uninit/common/src/commonTest/kotlin/uninit/common/fytix/EventBusTests.kt
new file mode 100644
index 0000000..ac7ccdc
--- /dev/null
+++ b/uninit/common/src/commonTest/kotlin/uninit/common/fytix/EventBusTests.kt
@@ -0,0 +1,35 @@
+package uninit.common.fytix
+
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal class SampleTest {
+
+ private val bus = EventBus()
+
+ @Test
+ fun testEventFire() {
+ var hit = false
+ bus.on("testEventFire") {
+ hit = true
+ }
+ assertEquals(false, hit)
+ bus.directEmit("testEventFire", "test")
+ assertEquals(true, hit)
+ }
+
+
+ // this fails bc comodification??? idk im too lazy to fix it
+// @Test
+// fun testOnce() {
+// var hit = 0
+// bus.once("testOnce") {
+// hit++
+// }
+// assertEquals(0, hit)
+// bus.directEmit("testOnce", "test")
+// assertEquals(1, hit)
+// bus.directEmit("testOnce", "test")
+// assertEquals(1, hit)
+// }
+}
\ No newline at end of file
diff --git a/uninit/common/src/desktopMain/kotlin/uninit/common/platform.desktop.kt b/uninit/common/src/desktopMain/kotlin/uninit/common/platform.desktop.kt
new file mode 100644
index 0000000..c677588
--- /dev/null
+++ b/uninit/common/src/desktopMain/kotlin/uninit/common/platform.desktop.kt
@@ -0,0 +1,17 @@
+package uninit.common
+
+import uninit.common.platform.OsFamily
+
+actual object Platform {
+ actual val osFamily: OsFamily
+ get() = when (System.getProperty("os.name")) {
+ "Mac OS X" -> OsFamily.MACOS
+ "Windows" -> OsFamily.WINDOWS
+ "Linux" -> OsFamily.LINUX
+ else -> OsFamily.ANDROID
+ }
+
+ actual fun vibrate(iosIntensity: Float, iosSharpness: Float, androidTime: Int) {
+ }
+
+}
\ No newline at end of file
diff --git a/uninit/common/src/desktopMain/kotlin/uninit/common/platform.kt b/uninit/common/src/desktopMain/kotlin/uninit/common/platform.kt
new file mode 100644
index 0000000..7aa4a23
--- /dev/null
+++ b/uninit/common/src/desktopMain/kotlin/uninit/common/platform.kt
@@ -0,0 +1,3 @@
+package uninit.common
+
+actual fun getTimeInMillis(): Long = System.currentTimeMillis()
\ No newline at end of file
diff --git a/uninit/common/src/desktopMain/kotlin/uninit/common/serialization/GsonAdapter.kt b/uninit/common/src/desktopMain/kotlin/uninit/common/serialization/GsonAdapter.kt
new file mode 100644
index 0000000..2e7ca48
--- /dev/null
+++ b/uninit/common/src/desktopMain/kotlin/uninit/common/serialization/GsonAdapter.kt
@@ -0,0 +1,276 @@
+package uninit.common.serialization
+
+import com.google.gson.JsonElement
+import com.google.gson.JsonParser
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.serialization.InternalSerializationApi
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.serializer
+import uninit.common.interfaces.IDynValue
+import java.io.File
+import kotlin.reflect.KClass
+import kotlin.reflect.KProperty
+
+class GsonAdapter(val filepath: String) {
+
+ val elem: JsonElement
+
+ init {
+ val f = File(filepath)
+ if (!f.exists()) {
+ f.createNewFile()
+ } else {
+ if (!f.canRead()) {
+ throw Exception("Can't read preferences file")
+ }
+ if (!f.canWrite()) {
+ throw Exception("Can't write preferences file")
+ }
+ }
+ elem = JsonParser.parseString(f.readText().ifEmpty { "{}" })
+
+
+ }
+
+ fun save() {
+ CoroutineScope(Dispatchers.IO).launch {
+ File(filepath).writeText(elem.toString())
+ }
+ }
+
+ fun value(key: String, defaultValue: String): IDynValue {
+ return object : IDynValue {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): String {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return el.asString
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.addProperty(targetName, value)
+
+ save()
+ }
+
+ }
+ }
+
+ fun value(key: String, defaultValue: Int): IDynValue {
+ return object : IDynValue {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return el.asInt
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.addProperty(targetName, value)
+
+ save()
+ }
+
+ }
+ }
+
+ fun value(key: String, defaultValue: Long): IDynValue {
+ return object : IDynValue {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return el.asLong
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: Long) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.addProperty(targetName, value)
+
+ save()
+ }
+
+ }
+ }
+
+ fun value(key: String, defaultValue: Float): IDynValue {
+ return object : IDynValue {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return el.asFloat
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: Float) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.addProperty(targetName, value)
+
+ save()
+ }
+
+ }
+ }
+
+ fun value(key: String, defaultValue: Boolean): IDynValue {
+ return object : IDynValue {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return el.asBoolean
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.addProperty(targetName, value)
+
+ save()
+ }
+
+ }
+ }
+
+ fun value(key: String, defaultValue: Set): IDynValue> {
+ return object : IDynValue> {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): Set {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return el.asJsonArray.map { it.asString }.toSet()
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: Set) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.add(targetName, JsonParser.parseString(value.toString()))
+
+ save()
+ }
+
+ }
+ }
+
+ @OptIn(InternalSerializationApi::class)
+ fun value(key: String, defaultValue: T, klass: KClass): IDynValue {
+ return object : IDynValue {
+ override fun getValue(thisRef: Any?, property: KProperty<*>): T {
+ var el = elem
+ for (k in key.split(".")) {
+ el = el.asJsonObject[k] ?: return defaultValue
+ }
+ return Json.decodeFromString(klass.serializer(), el.asString)
+ }
+
+ override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
+ var el = elem
+ val targetName = key.split(".").last()
+ for (k in key.split(".")) {
+ if (k == targetName) {
+ break
+ }
+ el = if (el.asJsonObject[k] != null) {
+ el.asJsonObject[k]
+ } else {
+ el.asJsonObject.add(k, JsonParser.parseString("{}"))
+ el.asJsonObject[k]
+ }
+ }
+ el.asJsonObject.remove(targetName)
+ el.asJsonObject.add(
+ targetName,
+ JsonParser.parseString(Json.encodeToString(klass.serializer(), value))
+ )
+
+ save()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/uninit/common/src/iosMain/kotlin/uninit/common/platform.ios.kt b/uninit/common/src/iosMain/kotlin/uninit/common/platform.ios.kt
new file mode 100644
index 0000000..d53071a
--- /dev/null
+++ b/uninit/common/src/iosMain/kotlin/uninit/common/platform.ios.kt
@@ -0,0 +1,16 @@
+package uninit.common
+
+import platform.AudioToolbox.AudioServicesPlaySystemSound
+import uninit.common.platform.OsFamily
+
+actual object Platform {
+ actual val osFamily: OsFamily
+ get() = OsFamily.IOS
+
+
+ actual fun vibrate(iosIntensity: Float, iosSharpness: Float, androidTime: Int) {
+ // TODO: Implement intensity and sharpness
+ AudioServicesPlaySystemSound(1352U)
+ }
+
+}
\ No newline at end of file
diff --git a/uninit/common/src/iosMain/kotlin/uninit/common/platform.kt b/uninit/common/src/iosMain/kotlin/uninit/common/platform.kt
new file mode 100644
index 0000000..925e1d4
--- /dev/null
+++ b/uninit/common/src/iosMain/kotlin/uninit/common/platform.kt
@@ -0,0 +1,10 @@
+package uninit.common
+
+import platform.Foundation.NSDate
+import platform.Foundation.date
+import platform.Foundation.timeIntervalSince1970
+
+actual fun getTimeInMillis(): Long {
+ val secs = NSDate.date().timeIntervalSince1970()
+ return (secs * 1000 + if (secs > 0) 0.5 else -0.5).toLong()
+}