Skip to content

Commit 14e938c

Browse files
committed
Voyager wasm support
1 parent 19da298 commit 14e938c

File tree

20 files changed

+207
-648
lines changed

20 files changed

+207
-648
lines changed

composeApp/build.gradle.kts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,41 +61,31 @@ kotlin {
6161
implementation(libs.kotlinx.coroutines)
6262
implementation(libs.bundles.ktor.common)
6363

64+
implementation(libs.voyager)
65+
6466
implementation(libs.kmmViewModel)
6567

6668
implementation(libs.koalaplot)
69+
implementation(libs.treemap.chart)
70+
implementation(libs.treemap.chart.compose)
6771
api(libs.compose.window.size)
68-
69-
7072
}
7173

7274
androidMain.dependencies {
73-
// workaround for https://github.com/JetBrains/compose-multiplatform/issues/4157
74-
implementation("androidx.compose.material3:material3:1.2.0")
7575
implementation(libs.compose.ui.tooling.preview)
7676
implementation(libs.androidx.activity.compose)
7777

7878
implementation(libs.ktor.client.android)
79-
implementation(libs.voyager)
80-
81-
implementation("io.github.overpas:treemap-chart:0.1.0")
82-
implementation("io.github.overpas:treemap-chart-compose:0.1.0")
8379
}
8480

8581
desktopMain.dependencies {
8682
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:${libs.versions.kotlinx.coroutines}")
8783
implementation(compose.desktop.currentOs)
8884
implementation(libs.ktor.client.java)
89-
90-
implementation("io.github.overpas:treemap-chart:0.1.0")
91-
implementation("io.github.overpas:treemap-chart-compose:0.1.0")
9285
}
9386

9487
appleMain.dependencies {
9588
implementation(libs.ktor.client.darwin)
96-
97-
implementation("io.github.overpas:treemap-chart:0.1.0")
98-
implementation("io.github.overpas:treemap-chart-compose:0.1.0")
9989
}
10090
}
10191
}

composeApp/src/androidMain/kotlin/dev/johnoreilly/climatetrace/MainActivity.kt

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,21 @@ import androidx.activity.ComponentActivity
77
import androidx.activity.compose.setContent
88
import androidx.compose.foundation.layout.Column
99
import androidx.compose.foundation.layout.padding
10-
import androidx.compose.material.icons.Icons
11-
import androidx.compose.material.icons.filled.ArrowBack
1210
import androidx.compose.material3.CenterAlignedTopAppBar
1311
import androidx.compose.material3.ExperimentalMaterial3Api
14-
import androidx.compose.material3.Icon
15-
import androidx.compose.material3.IconButton
1612
import androidx.compose.material3.MaterialTheme
1713
import androidx.compose.material3.Scaffold
1814
import androidx.compose.material3.Text
1915
import androidx.compose.runtime.Composable
20-
import androidx.compose.runtime.LaunchedEffect
2116
import androidx.compose.runtime.collectAsState
2217
import androidx.compose.runtime.getValue
23-
import androidx.compose.runtime.remember
2418
import androidx.compose.ui.Modifier
2519
import cafe.adriel.voyager.core.screen.Screen
2620
import cafe.adriel.voyager.navigator.LocalNavigator
2721
import cafe.adriel.voyager.navigator.Navigator
2822
import cafe.adriel.voyager.navigator.currentOrThrow
2923
import dev.johnoreilly.climatetrace.di.initKoin
30-
import dev.johnoreilly.climatetrace.remote.Country
31-
import dev.johnoreilly.climatetrace.ui.CountryInfoDetailedView
24+
import dev.johnoreilly.climatetrace.ui.CountryEmissionsScreen
3225
import dev.johnoreilly.climatetrace.ui.CountryListView
3326
import dev.johnoreilly.climatetrace.viewmodel.ClimateTraceViewModel
3427
import org.koin.compose.koinInject
@@ -82,48 +75,6 @@ class CountryListScreen : Screen {
8275
}
8376
}
8477
}
85-
86-
87-
data class CountryEmissionsScreen(val country: Country) : Screen {
88-
89-
@Composable
90-
override fun Content() {
91-
val navigator = LocalNavigator.currentOrThrow
92-
93-
val viewModel = koinInject<ClimateTraceViewModel>()
94-
val countryEmissionInfo by viewModel.countryEmissionInfo.collectAsState()
95-
val countryAssetEmissions by viewModel.countryAssetEmissions.collectAsState()
96-
val isLoadingCountryDetails by viewModel.isLoadingCountryDetails.collectAsState()
97-
98-
LaunchedEffect(country) {
99-
viewModel.fetchCountryDetails(country)
100-
}
101-
102-
Scaffold(
103-
topBar = {
104-
CenterAlignedTopAppBar(
105-
title = {
106-
Text("ClimateTraceKMP")
107-
},
108-
navigationIcon = {
109-
IconButton(onClick = { navigator.pop() }) {
110-
Icon(Icons.Filled.ArrowBack, contentDescription = "Back")
111-
}
112-
}
113-
)
114-
}
115-
) {
116-
Column(Modifier.padding(it)) {
117-
CountryInfoDetailedView(
118-
country,
119-
countryEmissionInfo,
120-
countryAssetEmissions,
121-
isLoadingCountryDetails
122-
)
123-
}
124-
}
125-
}
126-
}
12778
}
12879

12980

composeApp/src/commonMain/kotlin/App.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import androidx.compose.material3.MaterialTheme
22
import androidx.compose.runtime.Composable
3+
import cafe.adriel.voyager.navigator.Navigator
34
import dev.johnoreilly.climatetrace.di.commonModule
45
import dev.johnoreilly.climatetrace.ui.ClimateTraceScreen
56
import org.koin.compose.KoinApplication
@@ -11,7 +12,7 @@ fun App() {
1112
modules(commonModule())
1213
}) {
1314
MaterialTheme {
14-
ClimateTraceScreen()
15+
Navigator(screen = ClimateTraceScreen())
1516
}
1617
}
1718
}
Binary file not shown.

composeApp/src/androidMain/kotlin/ChartNode.kt renamed to composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/ui/ChartNode.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package dev.johnoreilly.climatetrace.ui
2+
13
import androidx.compose.runtime.Stable
24
import androidx.compose.ui.graphics.Color
35

@@ -25,4 +27,4 @@ sealed class ChartNode {
2527
override val percentage: Double,
2628
val color: Color?,
2729
) : ChartNode()
28-
}
30+
}

composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/ui/ClimateTraceScreen.kt

Lines changed: 63 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.compose.animation.core.animateDpAsState
77
import androidx.compose.animation.fadeIn
88
import androidx.compose.animation.fadeOut
99
import androidx.compose.foundation.background
10+
import androidx.compose.foundation.border
1011
import androidx.compose.foundation.clickable
1112
import androidx.compose.foundation.layout.Arrangement
1213
import androidx.compose.foundation.layout.Box
@@ -32,6 +33,7 @@ import androidx.compose.material3.IconButton
3233
import androidx.compose.material3.MaterialTheme
3334
import androidx.compose.material3.SearchBar
3435
import androidx.compose.material3.Text
36+
import androidx.compose.material3.VerticalDivider
3537
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
3638
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
3739
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
@@ -47,6 +49,9 @@ import androidx.compose.ui.Modifier
4749
import androidx.compose.ui.graphics.Color
4850
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
4951
import androidx.compose.ui.unit.dp
52+
import cafe.adriel.voyager.core.screen.Screen
53+
import cafe.adriel.voyager.navigator.LocalNavigator
54+
import cafe.adriel.voyager.navigator.currentOrThrow
5055
import dev.johnoreilly.climatetrace.remote.ClimateTraceApi
5156
import dev.johnoreilly.climatetrace.remote.Country
5257
import dev.johnoreilly.climatetrace.ui.utils.PanelState
@@ -57,82 +62,84 @@ import org.koin.core.component.inject
5762

5863

5964
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
60-
@Composable
61-
fun ClimateTraceScreen() {
62-
val windowSizeClass = calculateWindowSizeClass()
63-
val viewModel = koinInject<ClimateTraceViewModel>()
65+
class ClimateTraceScreen: Screen {
66+
@Composable
67+
override fun Content() {
68+
val navigator = LocalNavigator.currentOrThrow
69+
val windowSizeClass = calculateWindowSizeClass()
70+
val viewModel = koinInject<ClimateTraceViewModel>()
6471

65-
val countryList by viewModel.countryList.collectAsState()
66-
val selectedCountry by viewModel.selectedCountry.collectAsState()
67-
val countryEmissionInfo by viewModel.countryEmissionInfo.collectAsState()
68-
val countryAssetEmissions by viewModel.countryAssetEmissions.collectAsState()
72+
val countryList by viewModel.countryList.collectAsState()
73+
val selectedCountry by viewModel.selectedCountry.collectAsState()
74+
val countryEmissionInfo by viewModel.countryEmissionInfo.collectAsState()
75+
val countryAssetEmissions by viewModel.countryAssetEmissions.collectAsState()
6976

70-
val isLoadingCountries by viewModel.isLoadingCountries.collectAsState()
71-
val isLoadingCountryDetails by viewModel.isLoadingCountryDetails.collectAsState()
77+
val isLoadingCountries by viewModel.isLoadingCountries.collectAsState()
78+
val isLoadingCountryDetails by viewModel.isLoadingCountryDetails.collectAsState()
7279

7380

74-
val panelState = remember { PanelState() }
81+
val panelState = remember { PanelState() }
7582

76-
val animatedSize = if (panelState.splitter.isResizing) {
77-
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize
78-
} else {
79-
animateDpAsState(
80-
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize,
81-
SpringSpec(stiffness = Spring.StiffnessLow)
82-
).value
83-
}
83+
val animatedSize = if (panelState.splitter.isResizing) {
84+
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize
85+
} else {
86+
animateDpAsState(
87+
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize,
88+
SpringSpec(stiffness = Spring.StiffnessLow)
89+
).value
90+
}
8491

8592

86-
Row(Modifier.fillMaxSize()) {
93+
Row(Modifier.fillMaxSize()) {
8794

88-
if (windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact) {
89-
Column(Modifier.fillMaxWidth()) {
95+
if (windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact) {
96+
Column(Modifier.fillMaxWidth()) {
9097

91-
Box(Modifier.height(250.dp).fillMaxWidth().background(color = Color.LightGray)) {
92-
CountryListView(
93-
countryList = countryList,
94-
selectedCountry = selectedCountry,
95-
isLoading = isLoadingCountries
96-
) { country ->
97-
viewModel.fetchCountryDetails(country)
98+
Box(
99+
Modifier.height(250.dp).fillMaxWidth().background(color = Color.LightGray)
100+
) {
101+
CountryListView(
102+
countryList = countryList,
103+
selectedCountry = selectedCountry,
104+
isLoading = isLoadingCountries
105+
) { country ->
106+
viewModel.fetchCountryDetails(country)
107+
}
98108
}
99-
}
100-
101-
Spacer(modifier = Modifier.width(1.dp).fillMaxWidth())
102-
CountryInfoDetailedView(
103-
country = selectedCountry,
104-
countryEmissionInfo = countryEmissionInfo,
105-
countryAssetEmissionsList = countryAssetEmissions,
106-
isLoading = isLoadingCountryDetails
107-
)
108-
}
109-
} else {
110109

111-
ResizablePanel(
112-
Modifier.width(animatedSize).fillMaxHeight(),
113-
title = "Countries",
114-
state = panelState
115-
) {
110+
Spacer(modifier = Modifier.width(1.dp).fillMaxWidth())
111+
CountryInfoDetailedView(
112+
country = selectedCountry,
113+
countryEmissionInfo = countryEmissionInfo,
114+
countryAssetEmissionsList = countryAssetEmissions,
115+
isLoading = isLoadingCountryDetails
116+
)
117+
}
118+
} else {
116119

117-
//Box(Modifier.width(250.dp).fillMaxHeight().background(color = Color.LightGray)) {
120+
ResizablePanel(
121+
Modifier.width(animatedSize).fillMaxHeight(),
122+
title = "Countries",
123+
state = panelState
124+
) {
118125
CountryListView(
119126
countryList = countryList,
120127
selectedCountry = selectedCountry,
121128
isLoading = isLoadingCountries
122129
) { country ->
123130
viewModel.fetchCountryDetails(country)
124131
}
125-
//}
126-
}
132+
}
127133

128-
Spacer(modifier = Modifier.width(1.dp).fillMaxHeight())
129-
Box(Modifier.fillMaxHeight()) {
130-
CountryInfoDetailedView(
131-
country = viewModel.selectedCountry.value,
132-
countryEmissionInfo = countryEmissionInfo,
133-
countryAssetEmissionsList = countryAssetEmissions,
134-
isLoading = isLoadingCountryDetails
135-
)
134+
VerticalDivider(thickness = 1.dp, color = Color.DarkGray)
135+
Box(Modifier.fillMaxHeight()) {
136+
CountryInfoDetailedView(
137+
country = viewModel.selectedCountry.value,
138+
countryEmissionInfo = countryEmissionInfo,
139+
countryAssetEmissionsList = countryAssetEmissions,
140+
isLoading = isLoadingCountryDetails
141+
)
142+
}
136143
}
137144
}
138145
}

composeApp/src/androidMain/kotlin/actual.kt renamed to composeApp/src/commonMain/kotlin/dev/johnoreilly/climatetrace/ui/CountryAssetEmissionsInfoTreeMapChart.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
package dev.johnoreilly.climatetrace.ui
2+
13
import androidx.compose.foundation.background
24
import androidx.compose.foundation.border
35
import androidx.compose.foundation.clickable
@@ -29,13 +31,14 @@ import by.overpass.treemapchart.compose.TreemapChart
2931
import by.overpass.treemapchart.core.tree.Tree
3032
import by.overpass.treemapchart.core.tree.tree
3133
import dev.johnoreilly.climatetrace.remote.CountryAssetEmissionsInfo
34+
import dev.johnoreilly.climatetrace.ui.ChartNode
3235
import io.github.koalaplot.core.util.generateHueColorPalette
3336
import io.github.koalaplot.core.util.toString
3437
import kotlinx.coroutines.Dispatchers
3538
import kotlinx.coroutines.withContext
3639

3740
@Composable
38-
actual fun CountryAssetEmissionsInfoTreeMapChart(countryAssetEmissions: List<CountryAssetEmissionsInfo>) {
41+
fun CountryAssetEmissionsInfoTreeMapChart(countryAssetEmissions: List<CountryAssetEmissionsInfo>) {
3942
var tree by remember { mutableStateOf<Tree<ChartNode>?>(null) }
4043

4144
LaunchedEffect(countryAssetEmissions) {

0 commit comments

Comments
 (0)