improvements for kmp
This commit is contained in:
+6
-6
@@ -1,8 +1,8 @@
|
||||
plugins {
|
||||
alias(libs.plugins.multiplatform).apply(false)
|
||||
alias(libs.plugins.compose.compiler).apply(false)
|
||||
alias(libs.plugins.compose).apply(false)
|
||||
alias(libs.plugins.compose.hot.reload).apply(false)
|
||||
alias(libs.plugins.android.application).apply(false)
|
||||
alias(libs.plugins.kotlinx.serialization).apply(false)
|
||||
alias(libs.plugins.multiplatform) apply false
|
||||
alias(libs.plugins.compose.compiler) apply false
|
||||
alias(libs.plugins.compose) apply false
|
||||
alias(libs.plugins.compose.hot.reload) apply false
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.kotlinx.serialization) apply false
|
||||
}
|
||||
|
||||
+46
-67
@@ -2,8 +2,6 @@ import org.jetbrains.compose.ExperimentalComposeLibrary
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import java.util.*
|
||||
|
||||
plugins {
|
||||
@@ -15,21 +13,6 @@ plugins {
|
||||
alias(libs.plugins.kotlinx.serialization)
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll(
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-opt-in=kotlinx.coroutines.FlowPreview",
|
||||
"-Xexpect-actual-classes"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
compose.resources {
|
||||
nameOfResClass = "R"
|
||||
}
|
||||
|
||||
kotlin {
|
||||
androidTarget {
|
||||
compilerOptions {
|
||||
@@ -39,53 +22,48 @@ kotlin {
|
||||
|
||||
jvm()
|
||||
|
||||
if (providers.gradleProperty("include_ios").get().toBoolean()) {
|
||||
listOf(
|
||||
iosX64(),
|
||||
iosArm64(),
|
||||
iosSimulatorArm64()
|
||||
).forEach { iosTarget ->
|
||||
iosTarget.binaries.framework {
|
||||
baseName = "ComposeApp"
|
||||
isStatic = true
|
||||
}
|
||||
listOf(
|
||||
iosArm64(),
|
||||
iosSimulatorArm64()
|
||||
).forEach { iosTarget ->
|
||||
iosTarget.binaries.framework {
|
||||
baseName = "ComposeApp"
|
||||
isStatic = true
|
||||
}
|
||||
}
|
||||
|
||||
if (providers.gradleProperty("include_wasm").get().toBoolean()) {
|
||||
@OptIn(ExperimentalWasmDsl::class)
|
||||
wasmJs {
|
||||
outputModuleName = "composeApp"
|
||||
browser {
|
||||
val rootDirPath = project.rootDir.path
|
||||
val projectDirPath = project.projectDir.path
|
||||
commonWebpackConfig {
|
||||
outputFileName = "composeApp.js"
|
||||
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
|
||||
static = (static ?: mutableListOf()).apply {
|
||||
// Serve sources to debug inside browser
|
||||
add(rootDirPath)
|
||||
add(projectDirPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
binaries.executable()
|
||||
}
|
||||
js {
|
||||
browser()
|
||||
binaries.executable()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalWasmDsl::class)
|
||||
wasmJs {
|
||||
browser()
|
||||
binaries.executable()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
androidMain.dependencies {
|
||||
implementation(compose.preview)
|
||||
implementation(libs.androidx.activityCompose)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
implementation(libs.kstore.file)
|
||||
}
|
||||
|
||||
commonMain.dependencies {
|
||||
implementation(compose.runtime)
|
||||
implementation(compose.foundation)
|
||||
implementation(compose.material3)
|
||||
implementation(compose.materialIconsExtended)
|
||||
implementation(compose.components.resources)
|
||||
implementation(compose.components.uiToolingPreview)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
implementation(libs.coil)
|
||||
implementation(libs.coil.network.ktor)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.ktor.core)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.content.negotiation)
|
||||
implementation(libs.ktor.kotlinx.serialization.json)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
@@ -102,20 +80,12 @@ kotlin {
|
||||
}
|
||||
|
||||
commonTest.dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation(libs.kotlin.test)
|
||||
@OptIn(ExperimentalComposeLibrary::class)
|
||||
implementation(compose.uiTest)
|
||||
implementation(libs.kotlinx.coroutines.test)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(compose.uiTooling)
|
||||
implementation(libs.androidx.activityCompose)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
implementation(libs.kstore.file)
|
||||
}
|
||||
|
||||
jvmMain.dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation(libs.kotlinx.coroutines.swing)
|
||||
@@ -124,18 +94,14 @@ kotlin {
|
||||
implementation(libs.kstore.file)
|
||||
}
|
||||
|
||||
findByName("iosMain")?.run {
|
||||
dependencies {
|
||||
implementation(libs.ktor.client.darwin)
|
||||
implementation(libs.kstore.file)
|
||||
}
|
||||
iosMain.dependencies {
|
||||
implementation(libs.ktor.client.darwin)
|
||||
implementation(libs.kstore.file)
|
||||
}
|
||||
|
||||
findByName("wasmJsMain")?.run {
|
||||
dependencies {
|
||||
implementation(libs.kstore.storage)
|
||||
implementation(libs.ktor.client.js)
|
||||
}
|
||||
webMain.dependencies {
|
||||
implementation(libs.kstore.storage)
|
||||
implementation(libs.ktor.client.js)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,6 +177,10 @@ dependencies {
|
||||
debugImplementation(compose.uiTooling)
|
||||
}
|
||||
|
||||
compose.resources {
|
||||
nameOfResClass = "R"
|
||||
}
|
||||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "MainKt"
|
||||
@@ -222,3 +192,12 @@ compose.desktop {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions.freeCompilerArgs.addAll(
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-opt-in=kotlinx.coroutines.FlowPreview",
|
||||
"-Xexpect-actual-classes"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.meloda.overseerr
|
||||
|
||||
import android.os.Build
|
||||
|
||||
class AndroidPlatform : Platform {
|
||||
override val name: String = "Android ${Build.VERSION.SDK_INT}"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = AndroidPlatform()
|
||||
@@ -1,16 +1,5 @@
|
||||
package dev.meloda.overseerr.common
|
||||
|
||||
import android.app.Application
|
||||
import dev.meloda.overseerr.di.appModule
|
||||
import org.koin.core.context.startKoin
|
||||
|
||||
class AppGlobal : Application() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
startKoin {
|
||||
modules(appModule)
|
||||
}
|
||||
}
|
||||
}
|
||||
class AppGlobal : Application()
|
||||
|
||||
@@ -8,30 +8,34 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import dev.meloda.overseerr.datastore.SettingsController
|
||||
import dev.meloda.overseerr.di.appModule
|
||||
import dev.meloda.overseerr.screens.main.MainScreen
|
||||
import dev.meloda.overseerr.theme.AppTheme
|
||||
import io.github.aakira.napier.DebugAntilog
|
||||
import io.github.aakira.napier.Napier
|
||||
import org.koin.compose.KoinApplication
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
var appDir: String = ""
|
||||
|
||||
@Composable
|
||||
internal fun App() {
|
||||
LaunchedEffect(true) {
|
||||
Napier.base(DebugAntilog())
|
||||
}
|
||||
KoinApplication(application = { modules(appModule) }) {
|
||||
LaunchedEffect(true) {
|
||||
Napier.base(DebugAntilog())
|
||||
}
|
||||
|
||||
val settingsController: SettingsController = koinInject()
|
||||
val settings by settingsController.settings.collectAsStateWithLifecycle()
|
||||
val settingsController: SettingsController = koinInject()
|
||||
val settings by settingsController.settings.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(true) {
|
||||
settingsController.loadAppSettings()
|
||||
}
|
||||
LaunchedEffect(true) {
|
||||
settingsController.loadAppSettings()
|
||||
}
|
||||
|
||||
AppTheme(themeMode = settings.themeMode) {
|
||||
Surface(modifier = Modifier.fillMaxSize()) {
|
||||
MainScreen()
|
||||
AppTheme(themeMode = settings.themeMode) {
|
||||
Surface(modifier = Modifier.fillMaxSize()) {
|
||||
MainScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.meloda.overseerr
|
||||
|
||||
interface Platform {
|
||||
val name: String
|
||||
}
|
||||
|
||||
expect fun getPlatform(): Platform
|
||||
+13
-21
@@ -1,43 +1,35 @@
|
||||
package dev.meloda.overseerr.datastore
|
||||
|
||||
import dev.meloda.overseerr.ext.setValue
|
||||
import dev.meloda.overseerr.datastore.model.AppSettings
|
||||
import dev.meloda.overseerr.datastore.model.ThemeMode
|
||||
import dev.meloda.overseerr.ext.setValue
|
||||
import io.github.xxfast.kstore.KStore
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
interface SettingsController {
|
||||
val settings: StateFlow<AppSettings>
|
||||
|
||||
suspend fun saveAppSettings()
|
||||
suspend fun updateAppSettings(update: (AppSettings) -> AppSettings)
|
||||
suspend fun loadAppSettings(): AppSettings
|
||||
class SettingsController(
|
||||
private val store: KStore<AppSettings>,
|
||||
) {
|
||||
private val _settings = MutableStateFlow(AppSettings.EMPTY)
|
||||
val settings: StateFlow<AppSettings> = _settings.asStateFlow()
|
||||
|
||||
fun updateThemeMode(newThemeMode: ThemeMode)
|
||||
}
|
||||
|
||||
class SettingsControllerImpl(
|
||||
private val store: KStore<AppSettings>
|
||||
) : SettingsController {
|
||||
|
||||
override val settings = MutableStateFlow(AppSettings.EMPTY)
|
||||
|
||||
override suspend fun saveAppSettings() {
|
||||
suspend fun saveAppSettings() {
|
||||
store.set(settings.value)
|
||||
}
|
||||
|
||||
override suspend fun updateAppSettings(update: (AppSettings) -> AppSettings) {
|
||||
suspend fun updateAppSettings(update: (AppSettings) -> AppSettings) {
|
||||
store.set(update(settings.value))
|
||||
}
|
||||
|
||||
override suspend fun loadAppSettings(): AppSettings {
|
||||
suspend fun loadAppSettings(): AppSettings {
|
||||
val loadedSettings = store.get() ?: AppSettings.EMPTY
|
||||
settings.setValue { loadedSettings }
|
||||
_settings.setValue { loadedSettings }
|
||||
return loadedSettings
|
||||
}
|
||||
|
||||
override fun updateThemeMode(newThemeMode: ThemeMode) {
|
||||
settings.setValue { old -> old.copy(themeMode = newThemeMode) }
|
||||
fun updateThemeMode(newThemeMode: ThemeMode) {
|
||||
_settings.setValue { old -> old.copy(themeMode = newThemeMode) }
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,13 +1,11 @@
|
||||
package dev.meloda.overseerr.datastore.di
|
||||
|
||||
import dev.meloda.overseerr.datastore.SettingsController
|
||||
import dev.meloda.overseerr.datastore.SettingsControllerImpl
|
||||
import dev.meloda.overseerr.datastore.SettingsStoreProvider
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
val dataStoreModule = module {
|
||||
single { SettingsStoreProvider().provideStore() }
|
||||
singleOf(::SettingsControllerImpl) bind SettingsController::class
|
||||
singleOf(::SettingsController)
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
|
||||
data class AppSettings(
|
||||
val url: String? = null,
|
||||
val plexToken: String? = null,
|
||||
val themeMode: ThemeMode = ThemeMode.System,
|
||||
val themeMode: ThemeMode = ThemeMode.System
|
||||
) {
|
||||
companion object {
|
||||
val EMPTY: AppSettings = AppSettings()
|
||||
|
||||
-1
@@ -21,7 +21,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import dev.chrisbanes.haze.hazeSource
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
import dev.chrisbanes.haze.materials.HazeMaterials
|
||||
import dev.meloda.overseerr.screens.requests.RequestsViewModel
|
||||
import dev.meloda.overseerr.screens.requests.RequestsViewModelImpl
|
||||
import dev.meloda.overseerr.screens.requests.model.RequestsScreenState
|
||||
|
||||
-1
@@ -6,7 +6,6 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
|
||||
+1
-8
@@ -1,12 +1,5 @@
|
||||
import androidx.compose.ui.window.ComposeUIViewController
|
||||
import dev.meloda.overseerr.App
|
||||
import dev.meloda.overseerr.di.appModule
|
||||
import org.koin.core.context.startKoin
|
||||
import platform.UIKit.UIViewController
|
||||
|
||||
fun MainViewController(): UIViewController = ComposeUIViewController {
|
||||
startKoin {
|
||||
modules(appModule)
|
||||
}
|
||||
App()
|
||||
}
|
||||
fun MainViewController(): UIViewController = ComposeUIViewController { App() }
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.meloda.overseerr
|
||||
|
||||
import platform.UIKit.UIDevice
|
||||
|
||||
class IOSPlatform : Platform {
|
||||
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = IOSPlatform()
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package dev.meloda.overseerr.settings.model
|
||||
package dev.meloda.overseerr.datastore
|
||||
|
||||
import dev.meloda.overseerr.appDir
|
||||
import dev.meloda.overseerr.datastore.model.AppSettings
|
||||
import io.github.xxfast.kstore.KStore
|
||||
import io.github.xxfast.kstore.file.storeOf
|
||||
import kotlinx.io.files.Path
|
||||
@@ -1,6 +0,0 @@
|
||||
package dev.meloda.overseerr.model
|
||||
|
||||
internal actual class Platform actual constructor() {
|
||||
actual val name: String
|
||||
get() = "iOS"
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package dev.meloda.overseerr.network
|
||||
|
||||
import io.ktor.client.engine.HttpClientEngineFactory
|
||||
import io.ktor.client.engine.darwin.Darwin
|
||||
|
||||
actual class HttpClientEngineFactoryProvider actual constructor() {
|
||||
actual fun get(): HttpClientEngineFactory<*> = Darwin
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package dev.meloda.overseerr.network.model
|
||||
|
||||
import io.ktor.client.engine.*
|
||||
import io.ktor.client.engine.darwin.*
|
||||
|
||||
actual class HttpClientEngineFactoryProvider actual constructor() {
|
||||
actual fun get(): HttpClientEngineFactory<*> = Darwin
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.meloda.overseerr
|
||||
|
||||
class JsPlatform : Platform {
|
||||
override val name: String = "Web with Kotlin/JS"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = JsPlatform()
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package dev.meloda.overseerr.network
|
||||
|
||||
import io.ktor.client.engine.HttpClientEngineFactory
|
||||
import io.ktor.client.engine.js.Js
|
||||
|
||||
actual class HttpClientEngineFactoryProvider actual constructor() {
|
||||
actual fun get(): HttpClientEngineFactory<*> = Js
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.browser.window
|
||||
|
||||
@Composable
|
||||
actual fun ResizableWindow(content: @Composable () -> Unit) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(window.innerWidth.coerceIn(360..600).dp)
|
||||
.height(window.innerHeight.coerceIn(minimumValue = 360, maximumValue = null).dp)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.meloda.overseerr
|
||||
|
||||
class JVMPlatform : Platform {
|
||||
override val name: String = "Java ${System.getProperty("java.version")}"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = JVMPlatform()
|
||||
@@ -5,10 +5,8 @@ import androidx.compose.ui.window.application
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import dev.meloda.overseerr.App
|
||||
import dev.meloda.overseerr.appDir
|
||||
import dev.meloda.overseerr.di.appModule
|
||||
import io.github.aakira.napier.Napier
|
||||
import net.harawata.appdirs.AppDirsFactory
|
||||
import org.koin.compose.KoinApplication
|
||||
import java.awt.Dimension
|
||||
import java.io.File
|
||||
|
||||
@@ -28,10 +26,10 @@ fun main() = application {
|
||||
state = state,
|
||||
onCloseRequest = ::exitApplication
|
||||
) {
|
||||
window.minimumSize = Dimension(320, 480)
|
||||
|
||||
KoinApplication(application = { modules(appModule) }) {
|
||||
App()
|
||||
LaunchedEffect(Unit) {
|
||||
window.minimumSize = Dimension(320, 480)
|
||||
}
|
||||
|
||||
App()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.meloda.overseerr
|
||||
|
||||
class WasmPlatform : Platform {
|
||||
override val name: String = "Web with Kotlin/Wasm"
|
||||
}
|
||||
|
||||
actual fun getPlatform(): Platform = WasmPlatform()
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package dev.meloda.overseerr.network
|
||||
|
||||
import io.ktor.client.engine.*
|
||||
import io.ktor.client.engine.js.*
|
||||
import io.ktor.client.engine.HttpClientEngineFactory
|
||||
import io.ktor.client.engine.js.Js
|
||||
|
||||
actual class HttpClientEngineFactoryProvider actual constructor() {
|
||||
actual fun get(): HttpClientEngineFactory<*> = Js
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.ComposeViewport
|
||||
import dev.meloda.overseerr.App
|
||||
import dev.meloda.overseerr.di.appModule
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import org.koin.compose.KoinApplication
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
fun main() {
|
||||
ComposeViewport(document.body!!) {
|
||||
KoinApplication(application = { modules(appModule) }) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(window.innerWidth.coerceIn(360..600).dp)
|
||||
.height(window.innerHeight.coerceIn(minimumValue = 360, maximumValue = null).dp)
|
||||
) {
|
||||
App()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.browser.window
|
||||
|
||||
@Composable
|
||||
actual fun ResizableWindow(content: @Composable () -> Unit) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(window.innerWidth.coerceIn(360..600).dp)
|
||||
.height(window.innerHeight.coerceIn(minimumValue = 360, maximumValue = null).dp)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
-2
@@ -1,14 +1,12 @@
|
||||
package dev.meloda.overseerr.theme
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.ExperimentalBrowserHistoryApi
|
||||
import androidx.navigation.NavController
|
||||
|
||||
@Composable
|
||||
internal actual fun SystemAppearance(isDark: Boolean) {
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalBrowserHistoryApi::class)
|
||||
@Composable
|
||||
internal actual fun NavigationSettings(navController: NavController) {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.window.ComposeViewport
|
||||
import dev.meloda.overseerr.App
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
fun main() {
|
||||
ComposeViewport {
|
||||
ResizableWindow {
|
||||
App()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
expect fun ResizableWindow(content: @Composable () -> Unit)
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Wasm App</title>
|
||||
<title>Web App</title>
|
||||
<link type="text/css" rel="stylesheet" href="styles.css">
|
||||
<script type="application/javascript" src="composeApp.js"></script>
|
||||
</head>
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Temporary workaround for [KT-80582](https://youtrack.jetbrains.com/issue/KT-80582)
|
||||
*
|
||||
* This file should be safe to be removed once the ticket is closed and the project is updated to Kotlin version which solves that issue.
|
||||
*/
|
||||
config.watchOptions = config.watchOptions || {
|
||||
ignored: ["**/*.kt", "**/node_modules"]
|
||||
}
|
||||
|
||||
if (config.devServer) {
|
||||
config.devServer.static = config.devServer.static.map(file => {
|
||||
if (typeof file === "string") {
|
||||
return {
|
||||
directory: file,
|
||||
watch: false,
|
||||
}
|
||||
} else {
|
||||
return file
|
||||
}
|
||||
})
|
||||
}
|
||||
+4
-10
@@ -1,22 +1,16 @@
|
||||
#Kotlin
|
||||
kotlin.code.style=official
|
||||
kotlin.daemon.jvmargs=-Xmx4G
|
||||
#Gradle
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8
|
||||
org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
org.gradle.daemon=true
|
||||
org.gradle.parallel=true
|
||||
|
||||
#Kotlin
|
||||
kotlin.code.style=official
|
||||
kotlin.daemon.jvmargs=-Xmx4G
|
||||
kotlin.native.ignoreDisabledTargets=true
|
||||
kotlin.native.enableKlibsCrossCompilation=true
|
||||
|
||||
#Android
|
||||
android.useAndroidX=true
|
||||
android.nonTransitiveRClass=true
|
||||
|
||||
include_wasm=true
|
||||
include_ios=false
|
||||
|
||||
#Flip this to false when including the ios targets
|
||||
org.gradle.unsafe.configuration-cache=true
|
||||
|
||||
@@ -34,7 +34,7 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
|
||||
ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
|
||||
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
|
||||
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
|
||||
@@ -52,6 +52,8 @@ kstore-storage = { module = "io.github.xxfast:kstore-storage", version.ref = "ks
|
||||
appdirs = { module = "net.harawata:appdirs", version.ref = "appdirs" }
|
||||
napier = { module = "io.github.aakira:napier", version.ref = "napier" }
|
||||
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
|
||||
[plugins]
|
||||
multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
|
||||
+13
-13
@@ -4,32 +4,32 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google {
|
||||
content {
|
||||
includeGroupByRegex("com\\.android.*")
|
||||
includeGroupByRegex("com\\.google.*")
|
||||
includeGroupByRegex("androidx.*")
|
||||
includeGroupByRegex("android.*")
|
||||
mavenContent {
|
||||
includeGroupAndSubgroups("androidx")
|
||||
includeGroupAndSubgroups("com.android")
|
||||
includeGroupAndSubgroups("com.google")
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
google {
|
||||
content {
|
||||
includeGroupByRegex("com\\.android.*")
|
||||
includeGroupByRegex("com\\.google.*")
|
||||
includeGroupByRegex("androidx.*")
|
||||
includeGroupByRegex("android.*")
|
||||
mavenContent {
|
||||
includeGroupAndSubgroups("androidx")
|
||||
includeGroupAndSubgroups("com.android")
|
||||
includeGroupAndSubgroups("com.google")
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||
}
|
||||
|
||||
include(":composeApp")
|
||||
|
||||
Reference in New Issue
Block a user