1+ import  androidx.compose.foundation.layout.Column 
2+ import  androidx.compose.foundation.layout.Spacer 
3+ import  androidx.compose.foundation.layout.fillMaxHeight 
4+ import  androidx.compose.foundation.layout.fillMaxSize 
5+ import  androidx.compose.foundation.layout.padding 
6+ import  androidx.compose.foundation.layout.size 
7+ import  androidx.compose.foundation.layout.wrapContentSize 
8+ import  androidx.compose.foundation.rememberScrollState 
9+ import  androidx.compose.foundation.verticalScroll 
10+ import  androidx.compose.material.icons.Icons 
11+ import  androidx.compose.material.icons.automirrored.filled.ArrowBack 
12+ import  androidx.compose.material3.CenterAlignedTopAppBar 
13+ import  androidx.compose.material3.CircularProgressIndicator 
14+ import  androidx.compose.material3.ExperimentalMaterial3Api 
15+ import  androidx.compose.material3.Icon 
16+ import  androidx.compose.material3.IconButton 
117import  androidx.compose.material3.MaterialTheme 
18+ import  androidx.compose.material3.Scaffold 
19+ import  androidx.compose.material3.Text 
220import  androidx.compose.runtime.Composable 
21+ import  androidx.compose.runtime.LaunchedEffect 
22+ import  androidx.compose.runtime.collectAsState 
23+ import  androidx.compose.runtime.getValue 
24+ import  androidx.compose.ui.Alignment 
25+ import  androidx.compose.ui.Modifier 
26+ import  androidx.compose.ui.graphics.Color 
27+ import  androidx.compose.ui.text.style.TextAlign 
28+ import  androidx.compose.ui.unit.dp 
29+ import  androidx.navigation.compose.NavHost 
30+ import  androidx.navigation.compose.composable 
31+ import  androidx.navigation.compose.rememberNavController 
32+ import  androidx.navigation.toRoute 
333import  cafe.adriel.voyager.navigator.Navigator 
434import  dev.johnoreilly.climatetrace.di.commonModule 
35+ import  dev.johnoreilly.climatetrace.remote.Country 
536import  dev.johnoreilly.climatetrace.ui.ClimateTraceScreen 
37+ import  dev.johnoreilly.climatetrace.ui.CountryAssetEmissionsInfoTreeMapChart 
38+ import  dev.johnoreilly.climatetrace.ui.CountryListView 
39+ import  dev.johnoreilly.climatetrace.ui.SectorEmissionsPieChart 
40+ import  dev.johnoreilly.climatetrace.ui.YearSelector 
41+ import  dev.johnoreilly.climatetrace.ui.toPercent 
42+ import  dev.johnoreilly.climatetrace.viewmodel.CountryDetailsUIState 
43+ import  dev.johnoreilly.climatetrace.viewmodel.CountryDetailsViewModel 
44+ import  dev.johnoreilly.climatetrace.viewmodel.CountryListUIState 
45+ import  dev.johnoreilly.climatetrace.viewmodel.CountryListViewModel 
646import  org.jetbrains.compose.ui.tooling.preview.Preview 
747import  org.koin.compose.KoinApplication 
48+ import  org.koin.compose.koinInject 
849
950
1051@Preview
1152@Composable
12- fun  App () {
53+ fun  AppVoyagerNav () {
1354    KoinApplication (application =  {
1455        modules(commonModule())
1556    }) {
1657        MaterialTheme  {
1758            Navigator (screen =  ClimateTraceScreen ())
1859        }
1960    }
20- }
61+ }
62+ 
63+ @OptIn(ExperimentalMaterial3Api ::class )
64+ @Composable
65+ fun  AppJetpackBav () {
66+     KoinApplication (application =  {
67+         modules(commonModule())
68+     }) {
69+         MaterialTheme  {
70+             val  navController =  rememberNavController()
71+ 
72+             NavHost (
73+                 navController =  navController,
74+                 startDestination =  " countryList" 
75+             ) {
76+ 
77+                 composable(route =  " countryList" 
78+                     CountryListScreenJetpackNav  { country -> 
79+                         navController.navigate(country)
80+                     }
81+                 }
82+                 composable<Country > { backStackEntry -> 
83+                     val  country:  Country  =  backStackEntry.toRoute()
84+                     CountryInfoDetailedViewJetpackNav (country, popBack =  { navController.popBackStack() })
85+                 }
86+             }
87+         }
88+     }
89+ }
90+ 
91+ 
92+ @OptIn(ExperimentalMaterial3Api ::class )
93+ @Composable
94+ fun  CountryListScreenJetpackNav (countrySelected :  (country: Country ) ->  Unit ) {
95+     val  viewModel =  koinInject<CountryListViewModel >()
96+     val  viewState by viewModel.viewState.collectAsState()
97+ 
98+     Scaffold (
99+         topBar =  {
100+             CenterAlignedTopAppBar (title =  {
101+                     Text (" ClimateTraceKMP" 
102+                 }
103+             )
104+         }
105+     ) {
106+         Column (Modifier .padding(it)) {
107+             when  (val  state =  viewState) {
108+                 is  CountryListUIState .Loading  ->  {
109+                     Column (
110+                         modifier =  Modifier .fillMaxSize().fillMaxHeight()
111+                             .wrapContentSize(Alignment .Center )
112+                     ) {
113+                         CircularProgressIndicator ()
114+                     }
115+                 }
116+ 
117+                 is  CountryListUIState .Error  ->  {}
118+                 is  CountryListUIState .Success  ->  {
119+                     CountryListView (state.countryList, null , countrySelected)
120+                 }
121+             }
122+         }
123+     }
124+ }
125+ 
126+ 
127+ @Composable
128+ fun  CountryInfoDetailedViewJetpackNav (
129+     country :  Country ,
130+     popBack :  () ->  Unit 
131+ ) {
132+     val  countryDetailsViewModel:  CountryDetailsViewModel  =  koinInject()
133+     val  countryDetailsViewState by countryDetailsViewModel.viewState.collectAsState()
134+ 
135+     LaunchedEffect (country) {
136+         countryDetailsViewModel.setCountry(country)
137+     }
138+ 
139+     val  viewState =  countryDetailsViewState
140+     when  (viewState) {
141+         CountryDetailsUIState .NoCountrySelected  ->  {
142+             Column (
143+                 modifier =  Modifier .fillMaxSize()
144+                     .wrapContentSize(Alignment .Center )
145+             ) {
146+                 Text (text =  " No Country Selected." =  MaterialTheme .typography.titleMedium)
147+             }
148+         }
149+         is  CountryDetailsUIState .Loading  ->  {
150+             Column (
151+                 modifier =  Modifier .fillMaxSize()
152+                     .wrapContentSize(Alignment .Center )
153+             ) {
154+                 CircularProgressIndicator ()
155+             }
156+         }
157+         is  CountryDetailsUIState .Error  ->  { Text (" Error" 
158+         is  CountryDetailsUIState .Success  ->  {
159+             CountryInfoDetailedViewSuccessJetpackNav (viewState, popBack) {
160+                 countryDetailsViewModel.setYear(it)
161+             }
162+         }
163+     }
164+ }
165+ 
166+ 
167+ @OptIn(ExperimentalMaterial3Api ::class )
168+ @Composable
169+ fun  CountryInfoDetailedViewSuccessJetpackNav (viewState :  CountryDetailsUIState .Success , popBack :  () ->  Unit , onYearSelected :  (String ) ->  Unit ) {
170+ 
171+     Scaffold (
172+         topBar =  {
173+             CenterAlignedTopAppBar (
174+                 title =  { Text (viewState.country.name) },
175+                 navigationIcon =  {
176+                     IconButton (onClick =  { popBack() }) {
177+                         Icon (Icons .AutoMirrored .Filled .ArrowBack , contentDescription =  " Back" 
178+                     }
179+                 }
180+             )
181+         }
182+     ) {
183+ 
184+         Column (
185+             modifier =  Modifier 
186+                 .verticalScroll(rememberScrollState())
187+                 .fillMaxSize()
188+                 .padding(16 .dp),
189+             horizontalAlignment =  Alignment .CenterHorizontally 
190+         ) {
191+ 
192+             Text (
193+                 text =  viewState.country.name,
194+                 style =  MaterialTheme .typography.titleLarge,
195+                 textAlign =  TextAlign .Center 
196+             )
197+ 
198+             Spacer (modifier =  Modifier .size(16 .dp))
199+ 
200+             val  year =  viewState.year
201+             val  countryAssetEmissionsList =  viewState.countryAssetEmissionsList
202+             val  countryEmissionInfo =  viewState.countryEmissionInfo
203+ 
204+             YearSelector (year, onYearSelected)
205+             countryEmissionInfo?.let  {
206+                 val  co2 =  (countryEmissionInfo.emissions.co2 /  1_000_000 ).toInt()
207+                 val  percentage = 
208+                     (countryEmissionInfo.emissions.co2 /  countryEmissionInfo.worldEmissions.co2).toPercent(
209+                         2 
210+                     )
211+ 
212+                 Text (text =  " co2 = $co2  Million Tonnes ($year )" 
213+                 Text (text =  " rank = ${countryEmissionInfo.rank}  ($percentage )" 
214+ 
215+                 Spacer (modifier =  Modifier .size(16 .dp))
216+ 
217+                 val  filteredCountryAssetEmissionsList = 
218+                     countryAssetEmissionsList.filter { it.sector !=  null  }
219+                 if  (filteredCountryAssetEmissionsList.isNotEmpty()) {
220+                     SectorEmissionsPieChart (countryAssetEmissionsList)
221+                     Spacer (modifier =  Modifier .size(32 .dp))
222+                     CountryAssetEmissionsInfoTreeMapChart (countryAssetEmissionsList)
223+                 } else  {
224+                     Spacer (modifier =  Modifier .size(16 .dp))
225+                     Column (horizontalAlignment =  Alignment .CenterHorizontally ) {
226+                         Text (
227+                             " Invalid data" 
228+                             style =  MaterialTheme .typography.titleMedium.copy(color =  Color .Red ),
229+                             textAlign =  TextAlign .Center 
230+                         )
231+                     }
232+                 }
233+             }
234+         }
235+     }
236+ }
0 commit comments