Skip to content

Commit bfb6c75

Browse files
authored
Merge pull request #179 from joreilly/junie
Juni UI udpates
2 parents c19b947 + 7d63266 commit bfb6c75

File tree

10 files changed

+116
-41
lines changed

10 files changed

+116
-41
lines changed

.github/workflows/android.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ jobs:
1010
steps:
1111
- uses: actions/checkout@v5
1212
- name: set up JDK 21
13-
uses: actions/setup-java@v4
13+
uses: actions/setup-java@v5
1414
with:
1515
distribution: 'zulu'
1616
java-version: 21
1717
- name: Build android app
1818
run: ./gradlew assembleDebug
1919
- name: Run Unit Tests
20-
run: ./gradlew allTests
20+
run: ./gradlew :composeApp:jvmTest
2121

.github/workflows/build-and-publish-web.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212

1313
# Setup Java 1.8 environment for the next steps
1414
- name: Setup Java
15-
uses: actions/setup-java@v4
15+
uses: actions/setup-java@v5
1616
with:
1717
distribution: 'zulu'
1818
java-version: 17

.github/workflows/ios.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
runs-on: macos-latest
1414
steps:
1515
- uses: actions/checkout@v5
16-
- uses: actions/setup-java@v4
16+
- uses: actions/setup-java@v5
1717
with:
1818
distribution: 'zulu'
1919
java-version: 21

composeApp/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ kotlin {
8181
implementation(libs.koalaplot)
8282
implementation(libs.treemap.chart)
8383
implementation(libs.treemap.chart.compose)
84+
implementation("dev.carlsen.flagkit:flagkit:1.1.0")
8485
api(libs.compose.adaptive)
8586
api(libs.compose.adaptive.layout)
8687
}

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

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package dev.johnoreilly.climatetrace.ui
33
import androidx.compose.animation.AnimatedVisibility
44
import androidx.compose.animation.fadeIn
55
import androidx.compose.animation.fadeOut
6+
import androidx.compose.foundation.Image
67
import androidx.compose.foundation.clickable
78
import androidx.compose.foundation.layout.Arrangement
89
import androidx.compose.foundation.layout.Box
@@ -30,6 +31,7 @@ import androidx.compose.material3.SearchBar
3031
import androidx.compose.material3.SearchBarDefaults
3132
import androidx.compose.material3.Text
3233
import androidx.compose.material3.VerticalDivider
34+
import androidx.compose.material3.HorizontalDivider
3335
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
3436
import androidx.compose.runtime.Composable
3537
import androidx.compose.runtime.MutableState
@@ -45,6 +47,7 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
4547
import androidx.compose.ui.unit.dp
4648
import androidx.window.core.layout.WindowWidthSizeClass
4749
import cafe.adriel.voyager.core.screen.Screen
50+
import dev.carlsen.flagkit.FlagKit
4851
import dev.johnoreilly.climatetrace.remote.Country
4952
import dev.johnoreilly.climatetrace.ui.utils.PanelState
5053
import dev.johnoreilly.climatetrace.ui.utils.ResizablePanel
@@ -170,9 +173,9 @@ fun SearchableList(
170173
selectedCountry: Country?,
171174
countrySelected: (country: Country) -> Unit
172175
) {
173-
val filteredCountryList = countryList.filter {
174-
it.name.contains(searchQuery.value, ignoreCase = true)
175-
}
176+
val filteredCountryList = countryList
177+
.filter { it.name.contains(searchQuery.value, ignoreCase = true) || it.alpha2.contains(searchQuery.value, true) || it.alpha3.contains(searchQuery.value, true) }
178+
.sortedBy { it.name }
176179
val keyboardController = LocalSoftwareKeyboardController.current
177180
SearchBar(
178181
query = searchQuery.value,
@@ -253,20 +256,37 @@ fun CountryRow(
253256
selectedCountry: Country?,
254257
countrySelected: (country: Country) -> Unit
255258
) {
256-
Row(
257-
modifier = Modifier
258-
.fillMaxWidth()
259-
.clickable(onClick = { countrySelected(country) })
260-
.padding(8.dp),
261-
verticalAlignment = Alignment.CenterVertically
262-
) {
263-
Column {
264-
Text(
265-
text = country.name,
266-
style = if (country.name == selectedCountry?.name) MaterialTheme.typography.titleLarge else MaterialTheme.typography.bodyLarge
267-
)
259+
Column {
260+
Row(
261+
modifier = Modifier
262+
.fillMaxWidth()
263+
.clickable(onClick = { countrySelected(country) })
264+
.padding(horizontal = 16.dp, vertical = 12.dp),
265+
verticalAlignment = Alignment.CenterVertically
266+
) {
267+
val imageVector = FlagKit.getFlag(countryCode = country.alpha2)
268+
imageVector?.let {
269+
Image(
270+
imageVector = imageVector,
271+
contentDescription = country.name,
272+
)
273+
}
274+
275+
Spacer(modifier = Modifier.width(12.dp))
276+
277+
// Title and subtitle
278+
Column(Modifier.weight(1f)) {
279+
Text(
280+
text = country.name,
281+
style = if (country.name == selectedCountry?.name) MaterialTheme.typography.titleLarge else MaterialTheme.typography.bodyLarge
282+
)
283+
Text(
284+
text = "${country.continent}${country.alpha2} / ${country.alpha3}",
285+
style = MaterialTheme.typography.bodySmall,
286+
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
287+
)
288+
}
268289
}
290+
HorizontalDivider()
269291
}
270292
}
271-
272-

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ data class CountryEmissionsScreen(val country: Country) : Screen {
3535
topBar = {
3636
CenterAlignedTopAppBar(
3737
title = {
38-
Text("ClimateTraceKMP")
38+
Text(text = country.name)
3939
},
4040
navigationIcon = {
4141
IconButton(onClick = { navigator.pop() }) {
@@ -52,4 +52,5 @@ data class CountryEmissionsScreen(val country: Country) : Screen {
5252
}
5353
}
5454
}
55-
}
55+
}
56+

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

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package dev.johnoreilly.climatetrace.ui
33
import androidx.compose.foundation.clickable
44
import androidx.compose.foundation.layout.Box
55
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
67
import androidx.compose.foundation.layout.Spacer
78
import androidx.compose.foundation.layout.fillMaxSize
89
import androidx.compose.foundation.layout.padding
910
import androidx.compose.foundation.layout.size
1011
import androidx.compose.foundation.layout.wrapContentSize
1112
import androidx.compose.foundation.rememberScrollState
1213
import androidx.compose.foundation.verticalScroll
14+
import androidx.compose.material3.AssistChip
1315
import androidx.compose.material3.CircularProgressIndicator
1416
import androidx.compose.material3.DropdownMenu
1517
import androidx.compose.material3.DropdownMenuItem
@@ -64,35 +66,38 @@ fun CountryInfoDetailedViewSuccess(viewState: CountryDetailsUIState.Success, onY
6466
.verticalScroll(rememberScrollState())
6567
.fillMaxSize()
6668
.padding(16.dp),
67-
horizontalAlignment = Alignment.CenterHorizontally
69+
horizontalAlignment = Alignment.Start
6870
) {
69-
70-
Text(
71-
text = viewState.country.name,
72-
style = MaterialTheme.typography.titleLarge,
73-
textAlign = TextAlign.Center
74-
)
71+
// Header card with flag + country label info
72+
CountryHeader(viewState)
7573

7674
Spacer(modifier = Modifier.size(16.dp))
7775

7876
val year = viewState.year
7977
val countryAssetEmissionsList = viewState.countryAssetEmissionsList
8078
val countryEmissionInfo = viewState.countryEmissionInfo
8179

82-
YearSelector(year, viewState.availableYears, onYearSelected)
80+
// Year selector row
81+
Column {
82+
Text(text = "Year", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary)
83+
Spacer(modifier = Modifier.size(6.dp))
84+
YearSelector(year, viewState.availableYears, onYearSelected)
85+
}
86+
87+
Spacer(modifier = Modifier.size(12.dp))
88+
8389
countryEmissionInfo?.let {
8490
val co2 = (countryEmissionInfo.emissions.co2 / 1_000_000).toInt()
85-
val percentage =
86-
(countryEmissionInfo.emissions.co2 / countryEmissionInfo.worldEmissions.co2).toPercent(2)
91+
val percentage = (countryEmissionInfo.emissions.co2 / countryEmissionInfo.worldEmissions.co2).toPercent(2)
8792

88-
Text(text = "co2 = $co2 Million Tonnes ($year)")
89-
Text(text = "rank = ${countryEmissionInfo.rank} ($percentage)")
93+
// Key figures chips
94+
KeyFiguresRow(co2Mt = co2, rank = countryEmissionInfo.rank, share = percentage)
9095

9196
Spacer(modifier = Modifier.size(16.dp))
9297

93-
val filteredCountryAssetEmissionsList =
94-
countryAssetEmissionsList.filter { it.sector != null }
98+
val filteredCountryAssetEmissionsList = countryAssetEmissionsList.filter { it.sector != null }
9599
if (filteredCountryAssetEmissionsList.isNotEmpty()) {
100+
// Keep charts unchanged
96101
SectorEmissionsPieChart(countryAssetEmissionsList)
97102
Spacer(modifier = Modifier.size(32.dp))
98103
CountryAssetEmissionsInfoTreeMapChart(countryAssetEmissionsList)
@@ -110,6 +115,54 @@ fun CountryInfoDetailedViewSuccess(viewState: CountryDetailsUIState.Success, onY
110115
}
111116
}
112117

118+
@Composable
119+
private fun CountryHeader(viewState: CountryDetailsUIState.Success) {
120+
val c = viewState.country
121+
androidx.compose.material3.Surface(
122+
tonalElevation = 2.dp,
123+
shape = MaterialTheme.shapes.medium,
124+
color = MaterialTheme.colorScheme.surfaceVariant
125+
) {
126+
Column(modifier = Modifier.padding(16.dp)) {
127+
Text(
128+
text = c.name,
129+
style = MaterialTheme.typography.headlineSmall
130+
)
131+
Spacer(modifier = Modifier.size(4.dp))
132+
Text(
133+
text = "${c.continent}${c.alpha2} / ${c.alpha3}",
134+
style = MaterialTheme.typography.bodyMedium,
135+
color = MaterialTheme.colorScheme.onSurfaceVariant
136+
)
137+
}
138+
}
139+
}
140+
141+
@Composable
142+
private fun KeyFiguresRow(co2Mt: Int, rank: Int, share: String) {
143+
Row {
144+
KeyFigureChip(label = "CO₂ (Mt)", value = co2Mt.toString())
145+
Spacer(modifier = Modifier.size(8.dp))
146+
KeyFigureChip(label = "Rank", value = rank.toString())
147+
Spacer(modifier = Modifier.size(8.dp))
148+
KeyFigureChip(label = "World Share", value = share)
149+
}
150+
}
151+
152+
@Composable
153+
private fun KeyFigureChip(label: String, value: String) {
154+
AssistChip(
155+
onClick = {},
156+
label = {
157+
Column {
158+
Text(text = label, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSecondaryContainer)
159+
Text(text = value, style = MaterialTheme.typography.titleMedium)
160+
}
161+
}
162+
)
163+
}
164+
165+
113166

114167
@Composable
115168
fun YearSelector(selectedYear: String, availableYears: List<String>, onYearSelected: (String) -> Unit) {

composeApp/src/commonTest/kotlin/dev/johnoreilly/climatetrace/screen/ClimateTraceTestsScreen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class ClimateTraceScreenTest {
4444
onNodeWithText(country.name).assertExists()
4545
val millionTonnes = (countryEmissions.co2 / 1_000_000).toInt()
4646
val percentage = (countryEmissions.co2 / worldEmissions.co2).toPercent(2)
47-
onNodeWithText("co2 = $millionTonnes Million Tonnes ($year)").assertExists()
48-
onNodeWithText("rank = ${countryEmissionsInfo.rank} ($percentage)").assertExists()
47+
onNodeWithText("$millionTonnes").assertExists()
48+
onNodeWithText(percentage).assertExists()
4949
}
5050

5151
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ kotlin.incremental.wasm=true
33
kotlin.native.toolchain.enabled=false
44

55
#Gradle
6-
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
6+
org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
77

88

99
#Android

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

0 commit comments

Comments
 (0)