diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 95f04ba..ba8ff0e 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -59,6 +59,7 @@ kotlin { val desktopMain by getting { dependencies { implementation(libs.ktor.client.cio) + implementation(libs.kotlinx.coroutines.swing) implementation(compose.desktop.currentOs) } } diff --git a/composeApp/src/androidMain/kotlin/ch/parano/myice/MainActivity.kt b/composeApp/src/androidMain/kotlin/ch/parano/myice/MainActivity.kt index 45a4aaa..6f89b99 100644 --- a/composeApp/src/androidMain/kotlin/ch/parano/myice/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/ch/parano/myice/MainActivity.kt @@ -4,14 +4,14 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.material3.Text +import ch.parano.myice.auth.AndroidOAuthClient class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) setContent { - Text("MyIce") + App(oauthClient = AndroidOAuthClient(applicationContext)) } } } diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/App.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/App.kt new file mode 100644 index 0000000..8e55721 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ch/parano/myice/App.kt @@ -0,0 +1,77 @@ +package ch.parano.myice + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import ch.parano.myice.auth.AuthSettings +import ch.parano.myice.auth.OAuthClient +import ch.parano.myice.cache.ScheduleCache +import ch.parano.myice.network.ApiService +import ch.parano.myice.network.createHttpClient +import ch.parano.myice.ui.screens.EventDetailScreen +import ch.parano.myice.ui.screens.LoginScreen +import ch.parano.myice.ui.screens.ScheduleScreen +import ch.parano.myice.ui.theme.MyIceTheme +import ch.parano.myice.viewmodel.AuthState +import ch.parano.myice.viewmodel.AuthViewModel +import ch.parano.myice.viewmodel.EventDetailViewModel +import ch.parano.myice.viewmodel.ScheduleViewModel +import com.russhwolf.settings.Settings + +sealed class Screen { + data object Login : Screen() + data object Schedule : Screen() + data class EventDetail(val gameId: String, val account: String, val eventTitle: String) : Screen() +} + +@Composable +fun App( + oauthClient: OAuthClient, +) { + val apiService = remember { ApiService(createHttpClient()) } + val authSettings = remember { AuthSettings(Settings()) } + val cache = remember { ScheduleCache(Settings()) } + + val authViewModel = remember { AuthViewModel(apiService, authSettings, oauthClient) } + val scheduleViewModel = remember { ScheduleViewModel(apiService, cache, authSettings) } + val eventDetailViewModel = remember { EventDetailViewModel(apiService) } + + var currentScreen by remember { mutableStateOf(Screen.Login) } + + LaunchedEffect(Unit) { + authViewModel.init() + } + + val authState by authViewModel.state.collectAsState() + + LaunchedEffect(authState) { + currentScreen = when (authState) { + is AuthState.Authenticated -> Screen.Schedule + is AuthState.Unauthenticated -> Screen.Login + AuthState.Loading -> currentScreen + } + } + + MyIceTheme { + when (val screen = currentScreen) { + Screen.Login -> LoginScreen(viewModel = authViewModel) + Screen.Schedule -> ScheduleScreen( + scheduleViewModel = scheduleViewModel, + authViewModel = authViewModel, + onEventClick = { gameId, account, eventTitle -> + currentScreen = Screen.EventDetail(gameId, account, eventTitle) + }, + ) + is Screen.EventDetail -> EventDetailScreen( + gameId = screen.gameId, + account = screen.account, + eventTitle = screen.eventTitle, + viewModel = eventDetailViewModel, + ) + } + } +} diff --git a/composeApp/src/commonMain/kotlin/ch/parano/myice/Placeholder.kt b/composeApp/src/commonMain/kotlin/ch/parano/myice/Placeholder.kt deleted file mode 100644 index 0ab39f7..0000000 --- a/composeApp/src/commonMain/kotlin/ch/parano/myice/Placeholder.kt +++ /dev/null @@ -1 +0,0 @@ -package ch.parano.myice diff --git a/composeApp/src/desktopMain/kotlin/ch/parano/myice/Main.kt b/composeApp/src/desktopMain/kotlin/ch/parano/myice/Main.kt index ddbaca7..5e90936 100644 --- a/composeApp/src/desktopMain/kotlin/ch/parano/myice/Main.kt +++ b/composeApp/src/desktopMain/kotlin/ch/parano/myice/Main.kt @@ -1,11 +1,11 @@ package ch.parano.myice -import androidx.compose.material3.Text import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import ch.parano.myice.auth.DesktopOAuthClient fun main() = application { Window(onCloseRequest = ::exitApplication, title = "MyIce") { - Text("MyIce") + App(oauthClient = DesktopOAuthClient()) } } diff --git a/composeApp/src/iosMain/kotlin/ch/parano/myice/MainViewController.kt b/composeApp/src/iosMain/kotlin/ch/parano/myice/MainViewController.kt index db4a9c3..a1dd370 100644 --- a/composeApp/src/iosMain/kotlin/ch/parano/myice/MainViewController.kt +++ b/composeApp/src/iosMain/kotlin/ch/parano/myice/MainViewController.kt @@ -1,8 +1,8 @@ package ch.parano.myice -import androidx.compose.material3.Text import androidx.compose.ui.window.ComposeUIViewController +import ch.parano.myice.auth.IosOAuthClient fun MainViewController() = ComposeUIViewController { - Text("MyIce") + App(oauthClient = IosOAuthClient()) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d5ecc0c..130395a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "kto kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } multiplatform-settings = { module = "com.russhwolf:multiplatform-settings", version.ref = "multiplatform-settings" } multiplatform-settings-no-arg = { module = "com.russhwolf:multiplatform-settings-no-arg", version.ref = "multiplatform-settings" } diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift new file mode 100644 index 0000000..35a6711 --- /dev/null +++ b/iosApp/iosApp/ContentView.swift @@ -0,0 +1,10 @@ +import SwiftUI +import ComposeApp + +struct ContentView: UIViewRepresentable { + func makeUIView(context: Context) -> some UIView { + MainViewControllerKt.MainViewController() + } + + func updateUIView(_ uiView: UIViewType, context: Context) {} +} diff --git a/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist new file mode 100644 index 0000000..4a7a55c --- /dev/null +++ b/iosApp/iosApp/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UILaunchScreen + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CFBundleURLTypes + + + CFBundleURLName + ch.parano.myice + CFBundleURLSchemes + + myice + + + + + diff --git a/iosApp/iosApp/MyIceApp.swift b/iosApp/iosApp/MyIceApp.swift new file mode 100644 index 0000000..ff1867a --- /dev/null +++ b/iosApp/iosApp/MyIceApp.swift @@ -0,0 +1,11 @@ +import SwiftUI +import ComposeApp + +@main +struct MyIceApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +}