1
1
package ui.screen
2
2
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
4
10
import androidx.compose.foundation.background
5
11
import androidx.compose.foundation.clickable
6
12
import androidx.compose.foundation.layout.Arrangement
7
13
import androidx.compose.foundation.layout.Box
14
+ import androidx.compose.foundation.layout.BoxWithConstraints
8
15
import androidx.compose.foundation.layout.Column
9
16
import androidx.compose.foundation.layout.PaddingValues
10
17
import androidx.compose.foundation.layout.Row
@@ -20,14 +27,16 @@ import androidx.compose.foundation.lazy.itemsIndexed
20
27
import androidx.compose.foundation.rememberScrollState
21
28
import androidx.compose.foundation.shape.RoundedCornerShape
22
29
import androidx.compose.foundation.verticalScroll
23
- import androidx.compose.material3.Card
24
30
import androidx.compose.material3.Icon
25
31
import androidx.compose.material3.MaterialTheme
26
32
import androidx.compose.material3.Text
27
33
import androidx.compose.runtime.Composable
28
34
import androidx.compose.runtime.MutableState
35
+ import androidx.compose.runtime.collectAsState
36
+ import androidx.compose.runtime.getValue
29
37
import androidx.compose.runtime.mutableStateOf
30
38
import androidx.compose.runtime.remember
39
+ import androidx.compose.runtime.setValue
31
40
import androidx.compose.ui.Alignment
32
41
import androidx.compose.ui.Modifier
33
42
import androidx.compose.ui.draw.drawWithCache
@@ -40,29 +49,31 @@ import androidx.compose.ui.text.toUpperCase
40
49
import androidx.compose.ui.unit.TextUnit
41
50
import androidx.compose.ui.unit.TextUnitType
42
51
import androidx.compose.ui.unit.dp
52
+ import androidx.compose.ui.unit.sp
53
+ import cafe.adriel.voyager.core.model.rememberScreenModel
43
54
import cafe.adriel.voyager.core.screen.Screen
44
55
import cafe.adriel.voyager.navigator.LocalNavigator
45
56
import cafe.adriel.voyager.navigator.Navigator
46
57
import cafe.adriel.voyager.navigator.currentOrThrow
58
+ import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
59
+ import di.HomeScreenModelProvider
47
60
import model.Destination
61
+ import org.jetbrains.compose.resources.DrawableResource
48
62
import org.jetbrains.compose.resources.painterResource
49
63
import org.jetbrains.compose.resources.stringResource
50
64
import theme.PrimaryColor
51
- import theme.ReviewBodyBg
52
65
import theme.White
53
66
import theme.SecondTextColor
54
67
import theme.TextColor
55
- import theme.ThirdTextColor
56
- import theme.Yellow
57
68
import travelbuddy.composeapp.generated.resources.Res
69
+ import travelbuddy.composeapp.generated.resources.arrow_forward
58
70
import travelbuddy.composeapp.generated.resources.choose_date
59
71
import travelbuddy.composeapp.generated.resources.choose_meeting_point
60
72
import travelbuddy.composeapp.generated.resources.ci_location
61
73
import travelbuddy.composeapp.generated.resources.estimation
62
74
import travelbuddy.composeapp.generated.resources.facilities
63
75
import travelbuddy.composeapp.generated.resources.preview
64
76
import travelbuddy.composeapp.generated.resources.ratting
65
- import travelbuddy.composeapp.generated.resources.star
66
77
import travelbuddy.composeapp.generated.resources.type
67
78
import travelbuddy.composeapp.generated.resources.via
68
79
import ui.component.DestinationDetailChipItem
@@ -73,23 +84,24 @@ import ui.component.DestinationDetailSubItemDivider
73
84
import ui.component.DestinationDetailSubItemRatting
74
85
import ui.component.PrimaryButton
75
86
import ui.component.destinationDetailHeader
76
- import ui.viewmodel.HomeViewModel
87
+ import ui.viewmodel.HomeScreenModel
77
88
import util.BOTTOM_NAV_SPACE
78
89
import util.ImageItem
79
90
80
91
data class DestinationDetailScreen (val destination : Destination ) : Screen {
81
92
@Composable
82
93
override fun Content () {
94
+ val screenModel = HomeScreenModelProvider .homeScreenModel
83
95
val navigator = LocalNavigator .currentOrThrow
84
- DestinationDetailScreenView (navigator, destination)
96
+ DestinationDetailScreenView (navigator = navigator , destination = destination, viewModel = screenModel )
85
97
}
86
98
}
87
99
88
100
@Composable
89
101
fun DestinationDetailScreenView (
90
102
navigator : Navigator ,
91
103
destination : Destination ,
92
- viewModel : HomeViewModel = androidx.lifecycle.viewmodel.compose.viewModel { HomeViewModel () } ,
104
+ viewModel : HomeScreenModel ,
93
105
) {
94
106
val rememberThumbnail = remember { mutableStateOf(destination.thumbnail) }
95
107
Column (
@@ -123,6 +135,15 @@ fun DestinationDetailScreenView(
123
135
paddingValues = PaddingValues (start = 25 .dp, top = 36 .dp, end = 25 .dp, bottom = 36 .dp),
124
136
onClick = { viewModel.addToCart(destination) }
125
137
)
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
+ )
126
147
}
127
148
}
128
149
@@ -319,3 +340,64 @@ fun contentSection(destination: Destination, onImageClicked: (String) -> Unit) {
319
340
DestinationDetailFacilityItem (destination.facilities)
320
341
}
321
342
}
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
+ }
0 commit comments