Skip to content

Commit baad499

Browse files
Shared viewmodel added
1 parent 932548a commit baad499

File tree

13 files changed

+152
-56
lines changed

13 files changed

+152
-56
lines changed

composeApp/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ kotlin {
7171
implementation(libs.coil.network.ktor)
7272
implementation(libs.voyager.navigator)
7373
implementation(libs.voyager.tab.navigator)
74+
implementation(libs.voyager.screenmodel)
7475
implementation(libs.lifecycle.viewmodel.compose)
7576
implementation(libs.markdown.renderer)
7677
api(libs.compose.window.size)

composeApp/src/commonMain/kotlin/App.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import coil3.memory.MemoryCache
1818
import coil3.request.CachePolicy
1919
import coil3.request.crossfade
2020
import coil3.util.DebugLogger
21+
import di.HomeScreenModelProvider
2122
import okio.FileSystem
2223
import theme.TravelAppTheme
2324
import ui.component.BottomMenuBar
@@ -26,19 +27,18 @@ import ui.screen.CartTab
2627
import ui.screen.FavoriteTab
2728
import ui.screen.HomeTab
2829
import ui.screen.GeminiTab
29-
import ui.viewmodel.HomeViewModel
3030
import util.AnimateVisibility
3131

3232
@Composable
33-
internal fun App(
34-
viewModel: HomeViewModel = viewModel { HomeViewModel() }
35-
) {
33+
internal fun App() {
3634
TravelAppTheme {
3735

3836
setSingletonImageLoaderFactory { context ->
3937
getAsyncImageLoader(context)
4038
}
4139

40+
val viewModel = HomeScreenModelProvider.homeScreenModel
41+
4242
val bottomNavBarVisibility by viewModel.bottomNavBarVisible.collectAsState()
4343

4444
TabNavigator(HomeTab) {

composeApp/src/commonMain/kotlin/di/Koin.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package di
22

3+
import ui.viewmodel.HomeScreenModel
4+
35
//import org.koin.core.context.startKoin
46
//import org.koin.dsl.module
57
//
@@ -14,3 +16,9 @@ package di
1416
// )
1517
// }
1618
//}
19+
20+
object HomeScreenModelProvider {
21+
val homeScreenModel: HomeScreenModel by lazy {
22+
HomeScreenModel()
23+
}
24+
}

composeApp/src/commonMain/kotlin/ui/screen/ArticleDetailScreen.kt

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
package ui.screen
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.border
5-
import androidx.compose.foundation.layout.Arrangement
64
import androidx.compose.foundation.layout.Column
7-
import androidx.compose.foundation.layout.Row
85
import androidx.compose.foundation.layout.Spacer
96
import androidx.compose.foundation.layout.fillMaxSize
107
import androidx.compose.foundation.layout.fillMaxWidth
118
import androidx.compose.foundation.layout.offset
129
import androidx.compose.foundation.layout.padding
13-
import androidx.compose.foundation.lazy.LazyColumn
14-
import androidx.compose.foundation.lazy.items
1510
import androidx.compose.foundation.rememberScrollState
1611
import androidx.compose.foundation.shape.RoundedCornerShape
1712
import androidx.compose.foundation.verticalScroll
@@ -20,42 +15,39 @@ import androidx.compose.material3.Text
2015
import androidx.compose.runtime.Composable
2116
import androidx.compose.runtime.mutableStateOf
2217
import androidx.compose.runtime.remember
23-
import androidx.compose.ui.Alignment
2418
import androidx.compose.ui.Modifier
2519
import androidx.compose.ui.unit.dp
20+
import cafe.adriel.voyager.core.model.rememberScreenModel
2621
import cafe.adriel.voyager.core.screen.Screen
2722
import cafe.adriel.voyager.navigator.LocalNavigator
2823
import cafe.adriel.voyager.navigator.Navigator
2924
import cafe.adriel.voyager.navigator.currentOrThrow
25+
import di.HomeScreenModelProvider
3026
import model.Article
31-
import model.Destination
3227
import theme.Black
33-
import theme.BorderColor
3428
import theme.White
35-
import ui.component.ChildLayout
36-
import ui.component.VerticalScrollLayout
3729
import ui.component.article.ArticleBodyHeader
3830
import ui.component.article.ArticleDescription
39-
import ui.component.article.ArticleDestination
4031
import ui.component.article.ArticleHeader
4132
import ui.component.article.ArticleOther
4233
import ui.component.article.ArticlePharagraphs
43-
import ui.viewmodel.HomeViewModel
34+
import ui.viewmodel.HomeScreenModel
4435
import util.BOTTOM_NAV_SPACE
4536

4637
data class ArticleDetailScreen(val article: Article) : Screen {
4738
@Composable
4839
override fun Content() {
40+
val screenModel = HomeScreenModelProvider.homeScreenModel
4941
val navigator = LocalNavigator.currentOrThrow
50-
ArticleDetailScreenView(navigator, article)
42+
ArticleDetailScreenView(navigator = navigator, article = article, viewModel = screenModel)
5143
}
5244
}
5345

5446
@Composable
5547
fun ArticleDetailScreenView(
5648
navigator: Navigator,
5749
article: Article,
58-
viewModel: HomeViewModel = androidx.lifecycle.viewmodel.compose.viewModel { HomeViewModel() },
50+
viewModel: HomeScreenModel,
5951
) {
6052
val rememberThumbnail = remember { mutableStateOf(article.thumbnail) }
6153
Column(

composeApp/src/commonMain/kotlin/ui/screen/CartTab.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ import androidx.compose.runtime.remember
1616
import androidx.compose.ui.Modifier
1717
import androidx.compose.ui.text.style.TextAlign
1818
import androidx.compose.ui.unit.dp
19+
import cafe.adriel.voyager.core.model.rememberScreenModel
1920
import cafe.adriel.voyager.navigator.LocalNavigator
2021
import cafe.adriel.voyager.navigator.Navigator
2122
import cafe.adriel.voyager.navigator.currentOrThrow
2223
import cafe.adriel.voyager.navigator.tab.TabOptions
24+
import di.HomeScreenModelProvider
2325
import model.Destination
2426
import org.jetbrains.compose.resources.DrawableResource
2527
import org.jetbrains.compose.resources.StringResource
@@ -32,7 +34,7 @@ import travelbuddy.composeapp.generated.resources.menu_cart
3234
import ui.component.CartCard
3335
import ui.component.LoadItemAfterSafeCast
3436
import ui.component.Tabx
35-
import ui.viewmodel.HomeViewModel
37+
import ui.viewmodel.HomeScreenModel
3638
import util.BOTTOM_NAV_SPACE
3739

3840
data object CartTab : Tabx {
@@ -56,15 +58,16 @@ data object CartTab : Tabx {
5658

5759
@Composable
5860
override fun Content() {
61+
val screenModel = HomeScreenModelProvider.homeScreenModel
5962
val navigator = LocalNavigator.currentOrThrow
60-
CartScreenView(navigator)
63+
CartScreenView(navigator = navigator, viewModel = screenModel)
6164
}
6265
}
6366

6467
@Composable
6568
fun CartScreenView(
6669
navigator: Navigator,
67-
viewModel: HomeViewModel = androidx.lifecycle.viewmodel.compose.viewModel { HomeViewModel() },
70+
viewModel: HomeScreenModel,
6871
) {
6972
val cartItems by viewModel.cartItems.collectAsState()
7073

composeApp/src/commonMain/kotlin/ui/screen/DestinationDetailScreen.kt

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
package ui.screen
22

3-
import androidx.compose.foundation.Image
3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.animation.core.animateDpAsState
5+
import androidx.compose.animation.core.tween
6+
import androidx.compose.animation.expandIn
7+
import androidx.compose.animation.fadeIn
8+
import androidx.compose.animation.fadeOut
9+
import androidx.compose.animation.shrinkOut
410
import androidx.compose.foundation.background
511
import androidx.compose.foundation.clickable
612
import androidx.compose.foundation.layout.Arrangement
713
import androidx.compose.foundation.layout.Box
14+
import androidx.compose.foundation.layout.BoxWithConstraints
815
import androidx.compose.foundation.layout.Column
916
import androidx.compose.foundation.layout.PaddingValues
1017
import androidx.compose.foundation.layout.Row
@@ -20,14 +27,16 @@ import androidx.compose.foundation.lazy.itemsIndexed
2027
import androidx.compose.foundation.rememberScrollState
2128
import androidx.compose.foundation.shape.RoundedCornerShape
2229
import androidx.compose.foundation.verticalScroll
23-
import androidx.compose.material3.Card
2430
import androidx.compose.material3.Icon
2531
import androidx.compose.material3.MaterialTheme
2632
import androidx.compose.material3.Text
2733
import androidx.compose.runtime.Composable
2834
import androidx.compose.runtime.MutableState
35+
import androidx.compose.runtime.collectAsState
36+
import androidx.compose.runtime.getValue
2937
import androidx.compose.runtime.mutableStateOf
3038
import androidx.compose.runtime.remember
39+
import androidx.compose.runtime.setValue
3140
import androidx.compose.ui.Alignment
3241
import androidx.compose.ui.Modifier
3342
import androidx.compose.ui.draw.drawWithCache
@@ -40,29 +49,31 @@ import androidx.compose.ui.text.toUpperCase
4049
import androidx.compose.ui.unit.TextUnit
4150
import androidx.compose.ui.unit.TextUnitType
4251
import androidx.compose.ui.unit.dp
52+
import androidx.compose.ui.unit.sp
53+
import cafe.adriel.voyager.core.model.rememberScreenModel
4354
import cafe.adriel.voyager.core.screen.Screen
4455
import cafe.adriel.voyager.navigator.LocalNavigator
4556
import cafe.adriel.voyager.navigator.Navigator
4657
import cafe.adriel.voyager.navigator.currentOrThrow
58+
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
59+
import di.HomeScreenModelProvider
4760
import model.Destination
61+
import org.jetbrains.compose.resources.DrawableResource
4862
import org.jetbrains.compose.resources.painterResource
4963
import org.jetbrains.compose.resources.stringResource
5064
import theme.PrimaryColor
51-
import theme.ReviewBodyBg
5265
import theme.White
5366
import theme.SecondTextColor
5467
import theme.TextColor
55-
import theme.ThirdTextColor
56-
import theme.Yellow
5768
import travelbuddy.composeapp.generated.resources.Res
69+
import travelbuddy.composeapp.generated.resources.arrow_forward
5870
import travelbuddy.composeapp.generated.resources.choose_date
5971
import travelbuddy.composeapp.generated.resources.choose_meeting_point
6072
import travelbuddy.composeapp.generated.resources.ci_location
6173
import travelbuddy.composeapp.generated.resources.estimation
6274
import travelbuddy.composeapp.generated.resources.facilities
6375
import travelbuddy.composeapp.generated.resources.preview
6476
import travelbuddy.composeapp.generated.resources.ratting
65-
import travelbuddy.composeapp.generated.resources.star
6677
import travelbuddy.composeapp.generated.resources.type
6778
import travelbuddy.composeapp.generated.resources.via
6879
import ui.component.DestinationDetailChipItem
@@ -73,23 +84,24 @@ import ui.component.DestinationDetailSubItemDivider
7384
import ui.component.DestinationDetailSubItemRatting
7485
import ui.component.PrimaryButton
7586
import ui.component.destinationDetailHeader
76-
import ui.viewmodel.HomeViewModel
87+
import ui.viewmodel.HomeScreenModel
7788
import util.BOTTOM_NAV_SPACE
7889
import util.ImageItem
7990

8091
data class DestinationDetailScreen(val destination: Destination) : Screen {
8192
@Composable
8293
override fun Content() {
94+
val screenModel = HomeScreenModelProvider.homeScreenModel
8395
val navigator = LocalNavigator.currentOrThrow
84-
DestinationDetailScreenView(navigator, destination)
96+
DestinationDetailScreenView(navigator = navigator, destination = destination, viewModel = screenModel)
8597
}
8698
}
8799

88100
@Composable
89101
fun DestinationDetailScreenView(
90102
navigator: Navigator,
91103
destination: Destination,
92-
viewModel: HomeViewModel = androidx.lifecycle.viewmodel.compose.viewModel { HomeViewModel() },
104+
viewModel: HomeScreenModel,
93105
) {
94106
val rememberThumbnail = remember { mutableStateOf(destination.thumbnail) }
95107
Column(
@@ -123,6 +135,15 @@ fun DestinationDetailScreenView(
123135
paddingValues = PaddingValues(start = 25.dp, top = 36.dp, end = 25.dp, bottom = 36.dp),
124136
onClick = { viewModel.addToCart(destination) }
125137
)
138+
139+
GeminiRoundButton(
140+
viewModel = viewModel,
141+
modifier = Modifier
142+
.align(Alignment.CenterHorizontally),
143+
logo = Res.drawable.arrow_forward,
144+
destination = destination,
145+
navigator = navigator
146+
)
126147
}
127148
}
128149

@@ -319,3 +340,64 @@ fun contentSection(destination: Destination, onImageClicked: (String) -> Unit) {
319340
DestinationDetailFacilityItem(destination.facilities)
320341
}
321342
}
343+
344+
@Composable
345+
fun GeminiRoundButton(
346+
viewModel: HomeScreenModel,
347+
modifier: Modifier = Modifier,
348+
logo: DrawableResource,
349+
destination: Destination,
350+
navigator: Navigator
351+
) {
352+
var isExpanded by remember { mutableStateOf(true) }
353+
val navigateToGemini by viewModel.navigateToGemini.collectAsState()
354+
if (navigateToGemini.first) {
355+
LocalNavigator.current?.pop()
356+
LocalTabNavigator.current.current = GeminiTab
357+
}
358+
359+
// Animate width change
360+
val buttonWidth by animateDpAsState(
361+
targetValue = if (isExpanded) 220.dp else 100.dp,
362+
animationSpec = tween(durationMillis = 300)
363+
)
364+
365+
BoxWithConstraints(
366+
modifier = modifier
367+
.padding(end = 16.dp, bottom = 36.dp)
368+
.width(buttonWidth)
369+
.background(color = PrimaryColor, shape = RoundedCornerShape(8.dp))
370+
.clickable {
371+
if (isExpanded) {
372+
viewModel.navigateToGimini(Pair(true, destination))
373+
}
374+
isExpanded = !isExpanded
375+
},
376+
contentAlignment = Alignment.Center
377+
) {
378+
Row(
379+
modifier = Modifier.padding(vertical = 8.dp, horizontal = 4.dp),
380+
verticalAlignment = Alignment.CenterVertically,
381+
horizontalArrangement = Arrangement.spacedBy(8.dp)
382+
) {
383+
Icon(
384+
painter = painterResource(logo),
385+
contentDescription = null,
386+
tint = Color.White,
387+
modifier = Modifier.size(24.dp)
388+
)
389+
AnimatedVisibility(
390+
visible = isExpanded,
391+
enter = fadeIn() + expandIn(),
392+
exit = fadeOut() + shrinkOut()
393+
) {
394+
Text(
395+
text = "Explore with Gemini",
396+
color = Color.White,
397+
style = MaterialTheme.typography.bodyLarge,
398+
fontSize = 16.sp
399+
)
400+
}
401+
}
402+
}
403+
}

composeApp/src/commonMain/kotlin/ui/screen/FavoriteTab.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
2121
import cafe.adriel.voyager.navigator.Navigator
2222
import cafe.adriel.voyager.navigator.currentOrThrow
2323
import cafe.adriel.voyager.navigator.tab.TabOptions
24+
import di.HomeScreenModelProvider
2425
import model.Destination
2526
import org.jetbrains.compose.resources.DrawableResource
2627
import org.jetbrains.compose.resources.StringResource
@@ -34,7 +35,7 @@ import travelbuddy.composeapp.generated.resources.fav_tab
3435
import travelbuddy.composeapp.generated.resources.favorite_destination
3536
import travelbuddy.composeapp.generated.resources.menu_fav
3637
import ui.component.Tabx
37-
import ui.viewmodel.HomeViewModel
38+
import ui.viewmodel.HomeScreenModel
3839
import util.BOTTOM_NAV_SPACE
3940

4041
data object FavoriteTab : Tabx {
@@ -65,16 +66,17 @@ data object FavoriteTab : Tabx {
6566
object FavoriteScreen : Screen {
6667
@Composable
6768
override fun Content() {
69+
val screenModel = HomeScreenModelProvider.homeScreenModel
6870
val navigator = LocalNavigator.currentOrThrow
69-
FavoriteScreenView(navigator)
71+
FavoriteScreenView(navigator = navigator, viewModel = screenModel)
7072
}
7173
}
7274

7375

7476
@Composable
7577
fun FavoriteScreenView(
7678
navigator: Navigator,
77-
viewModel: HomeViewModel = androidx.lifecycle.viewmodel.compose.viewModel { HomeViewModel() },
79+
viewModel: HomeScreenModel,
7880
) {
7981
val favorites by viewModel.favorites.collectAsState()
8082

0 commit comments

Comments
 (0)