Skip to content

Commit

Permalink
feat: solve kotlin 2.0 issue due to expect-actual operator for value …
Browse files Browse the repository at this point in the history
…class
  • Loading branch information
isfaaghyth committed Aug 26, 2024
1 parent bbb55a6 commit 803e682
Show file tree
Hide file tree
Showing 22 changed files with 279 additions and 107 deletions.
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ kotlin {
implementation(libs.androidx.activity.compose)
implementation(libs.common.koin.android)
implementation(libs.androidx.datastore)
implementation(libs.androidx.compose.windowsizeclass)
}

commonMain.dependencies {
// Libraries
implementation(project(":gdg-ui"))
Expand Down
36 changes: 27 additions & 9 deletions app/src/androidMain/kotlin/id/gdg/app/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,39 @@ package id.gdg.app
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import id.gdg.app.ui.AppContent
import id.gdg.ui.DarkColorPalette
import id.gdg.ui.LightColorPalette
import id.gdg.ui.androidx.compose.material3.windowsizeclass.CommonWindowSizeClass
import id.gdg.ui.androidx.compose.material3.windowsizeclass.LocalWindowSizeClass
import id.gdg.ui.androidx.compose.material3.windowsizeclass.calculateWindowSizeClass

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
App()
val colors = if (isSystemInDarkTheme()) DarkColorPalette else LightColorPalette
val windowSizeClass: CommonWindowSizeClass = calculateWindowSizeClass(this)

CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
MaterialTheme(
colorScheme = colors
) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
AppContent()
}
}
}
}
}
}

@Preview
@Composable
fun AppAndroidPreview() {
App()
}
30 changes: 25 additions & 5 deletions app/src/commonMain/kotlin/id/gdg/app/ui/AppContent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import id.gdg.app.AppViewModel
import id.gdg.app.di.ViewModelFactory
import id.gdg.app.ui.screen.EventDetailScreen
import id.gdg.app.ui.screen.MainScreen
import id.gdg.app.ui.screen.OnboardingScreen
import id.gdg.app.ui.screen.SplashScreen
Expand All @@ -23,12 +26,12 @@ fun AppContent(
Scaffold { innerPadding ->
NavHost(
navController = navController,
startDestination = AppRouter.Onboarding.route, //defaultRoute(state.activeChapterId),
startDestination = AppRouter.OnboardingRoute, //defaultRoute(state.activeChapterId),
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
composable(route = AppRouter.Splash.route) {
composable(route = AppRouter.SplashRoute) {
SplashScreen {
navController.navigateTo(
from = AppRouter.Splash,
Expand All @@ -37,7 +40,7 @@ fun AppContent(
}
}

composable(route = AppRouter.Onboarding.route) {
composable(route = AppRouter.OnboardingRoute) {
OnboardingScreen(
chapterList = viewModel.chapterList,
onChapterSelected = { chapterId ->
Expand All @@ -52,8 +55,25 @@ fun AppContent(
)
}

composable(route = AppRouter.Home.route) {
MainScreen(viewModel)
composable(route = AppRouter.HomeRoute) {
MainScreen(
viewModel = viewModel,
navigateToDetailScreen = { eventId ->
navController.navigate(AppRouter.constructEventDetailRoute(eventId))
}
)
}

composable(
route = AppRouter.EventDetailRoute,
arguments = listOf(navArgument(AppRouter.ArgumentEventId) { type = NavType.StringType })
) { backStackEntry ->
val eventId = backStackEntry.arguments?.getString(AppRouter.ArgumentEventId).orEmpty()

EventDetailScreen(
viewModel = viewModel,
eventId = eventId
)
}
}
}
Expand Down
24 changes: 21 additions & 3 deletions app/src/commonMain/kotlin/id/gdg/app/ui/AppRouter.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
package id.gdg.app.ui

import id.gdg.app.ui.state.EventDetailUiModel

sealed class AppRouter(val route: String) {

data object Splash : AppRouter("splash")
data object Onboarding : AppRouter("onboarding")
data object Home : AppRouter("home")
data object Splash : AppRouter(SplashRoute)
data object Onboarding : AppRouter(OnboardingRoute)
data object Home : AppRouter(HomeRoute)

data class EventDetail(val eventId: Int) : AppRouter(EventDetailRoute)

companion object {
val SplashRoute get() = "splash"
val OnboardingRoute get() = "onboarding"

val HomeRoute get() = "home"

// SAMPAH
val EventDetailRoute get() = "detail/{$ArgumentEventId}"
fun constructEventDetailRoute(eventId: String) = EventDetailRoute
.replace("{$ArgumentEventId}", eventId)

val ArgumentEventId get() = "eventId"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package id.gdg.app.ui.screen

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import id.gdg.app.AppViewModel
import id.gdg.app.ui.AppEvent

@Composable
fun EventDetailScreen(viewModel: AppViewModel, eventId: String) {
val eventDetailUiState by viewModel.eventDetailUiState.collectAsState()

LaunchedEffect(Unit) {
if (eventId.isNotEmpty()) {
viewModel.sendEvent(AppEvent.EventDetail(eventId.toInt()))
}
}

Box {
AnimatedVisibility(eventDetailUiState.state.isLoading) {
CircularProgressIndicator()
}

when {
eventDetailUiState.state.isSuccess -> {
Text(text = "${eventDetailUiState.detail}")
}
eventDetailUiState.state.isFail -> {
Row {
Text("gagal loading nih, refresh yuk")
Button(
onClick = {}
) {
Text("Refresh")
}
}
}
}
}
}
91 changes: 88 additions & 3 deletions app/src/commonMain/kotlin/id/gdg/app/ui/screen/MainScreen.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,116 @@
package id.gdg.app.ui.screen

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
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.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.unit.dp
import id.gdg.app.AppViewModel
import id.gdg.app.ui.AppEvent
import id.gdg.app.ui.screen.content.PreviousEventContent
import id.gdg.app.ui.screen.content.UpcomingEventContent
import id.gdg.app.ui.state.ChapterUiModel
import id.gdg.ui.TwoPanelScaffold
import id.gdg.ui.TwoPanelScaffoldAnimationSpec
import id.gdg.ui.androidx.compose.material3.windowsizeclass.CommonWindowSizeClass
import id.gdg.ui.androidx.compose.material3.windowsizeclass.CommonWindowWidthSizeClass
import id.gdg.ui.androidx.compose.material3.windowsizeclass.LocalWindowSizeClass

@Composable
fun MainScreen(viewModel: AppViewModel) {
fun MainScreen(
viewModel: AppViewModel,
navigateToDetailScreen: (String) -> Unit
) {
val chapterUiState by viewModel.chapterUiState.collectAsState()
var selectedEventId by rememberSaveable { mutableStateOf("") }

val windowSizeClazz: CommonWindowSizeClass = LocalWindowSizeClass.current
var hasDetailOpened: Boolean? by rememberSaveable { mutableStateOf(null) }
var showSidePanel by rememberSaveable {
mutableStateOf(hasDetailOpened != null).also {
println("showsidepanel: ${it.value}")
}
}

LaunchedEffect(Unit) {
viewModel.sendEvent(AppEvent.InitialContent)
}

LaunchedEffect(windowSizeClazz) {
hasDetailOpened =
hasDetailOpened.takeIf { windowSizeClazz.widthSizeClass != CommonWindowWidthSizeClass.Compact }
println("hasdetail: $hasDetailOpened")
println("apaini: ${windowSizeClazz.widthSizeClass != CommonWindowWidthSizeClass.Compact}")
showSidePanel = hasDetailOpened != null
}

TwoPanelScaffold(
panelVisibility = showSidePanel,
animationSpec = TwoPanelScaffoldAnimationSpec(
finishedListener = { fraction -> if (fraction == 1f) hasDetailOpened = null }
),
body = {
MainScreenView(
chapterUiState = chapterUiState,
onEventDetailClicked = {
// If the screen size is compact (or mobile device screen size), then
// navigate to detail page with router. Otherwise, render the [panel].
if (windowSizeClazz.widthSizeClass == CommonWindowWidthSizeClass.Compact) {
navigateToDetailScreen(it)
return@MainScreenView
}

selectedEventId = it
hasDetailOpened = true
showSidePanel = true
},
onRefreshPreviousContentClicked = {
viewModel.sendEvent(AppEvent.FetchPreviousEvent)
}
)
},
panel = {
Surface(tonalElevation = 1.dp) {
if (hasDetailOpened != null) {
EventDetailScreen(
viewModel = viewModel,
eventId = selectedEventId
)
}
}
}
)
}

@Composable
fun MainScreenView(
chapterUiState: ChapterUiModel,
onEventDetailClicked: (String) -> Unit,
onRefreshPreviousContentClicked: () -> Unit
) {
Column {
UpcomingEventContent(chapterUiState.upcomingEvent)

Button(
onClick = {
onEventDetailClicked("60014")
}
) {
Text("Show Detail")
}

PreviousEventContent(
data = chapterUiState.previousEvents,
onRefreshContent = {
viewModel.sendEvent(AppEvent.FetchPreviousEvent)
onRefreshPreviousContentClicked()
}
)
}
}
}
34 changes: 33 additions & 1 deletion app/src/iosMain/kotlin/id/gdg/app/MainViewController.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
@file:Suppress("FunctionName")

package id.gdg.app

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.window.ComposeUIViewController
import id.gdg.app.ui.AppContent
import id.gdg.ui.DarkColorPalette
import id.gdg.ui.LightColorPalette
import id.gdg.ui.androidx.compose.material3.windowsizeclass.LocalWindowSizeClass
import id.gdg.ui.androidx.compose.material3.windowsizeclass.CommonWindowSizeClass
import id.gdg.ui.androidx.compose.material3.windowsizeclass.calculateWindowSizeClass

fun MainViewController() = ComposeUIViewController {
BoxWithConstraints {
val colors = if (isSystemInDarkTheme()) DarkColorPalette else LightColorPalette
val windowSizeClass: CommonWindowSizeClass = calculateWindowSizeClass(DpSize(maxWidth, maxHeight))

fun MainViewController() = ComposeUIViewController { App() }
CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
MaterialTheme(colorScheme = colors) {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
AppContent()
}
}
}
}
}
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ plugins {
alias(libs.plugins.jetbrainsCompose) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
alias(libs.plugins.kotlinxSerialization) apply false
alias(libs.plugins.kover) apply true
}
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 803e682

Please sign in to comment.