@@ -13,6 +13,7 @@ import androidx.compose.runtime.*
1313import androidx.compose.ui.Alignment
1414import androidx.compose.ui.ExperimentalComposeUiApi
1515import androidx.compose.ui.Modifier
16+ import androidx.compose.ui.draw.alpha
1617import androidx.compose.ui.draw.clip
1718import androidx.compose.ui.hapticfeedback.HapticFeedbackType
1819import androidx.compose.ui.layout.ContentScale
@@ -21,27 +22,39 @@ import androidx.compose.ui.text.font.FontWeight
2122import androidx.compose.ui.text.style.TextAlign
2223import androidx.compose.ui.text.style.TextOverflow
2324import androidx.compose.ui.unit.dp
25+ import androidx.compose.ui.window.Dialog
2426import coil3.compose.AsyncImage
27+ import kotlinx.coroutines.launch
2528import kotlinx.serialization.encodeToString
2629import kotlinx.serialization.json.Json
2730import neth.iecal.trease.Constants
2831import neth.iecal.trease.api.TreeRepository
2932import neth.iecal.trease.models.TreeData
3033import neth.iecal.trease.models.TreeUiState
3134import neth.iecal.trease.utils.CacheManager
35+ import neth.iecal.trease.utils.TreePurchaseManager
36+ import neth.iecal.trease.viewmodels.HomeScreenViewModel
3237
3338@OptIn(ExperimentalMaterial3Api ::class , ExperimentalComposeUiApi ::class )
3439@Composable
3540fun GrowTreeBottomSheet (
3641 onDismiss : () -> Unit ,
37- onSelected : (TreeData ) -> Unit ,
42+ onAddToCanvas : (TreeData ) -> Unit ,
3843 onShowWitheredTrees : ()-> Unit ,
44+ viewModel : HomeScreenViewModel ,
3945) {
40- // State
4146 var uiState by remember { mutableStateOf<TreeUiState >(TreeUiState .Loading ) }
4247 var selectedTree by remember { mutableStateOf<TreeData ?>(null ) }
4348
49+ var purchasedTrees by remember { mutableStateOf(emptyList<String >()) }
50+ val coroutine = rememberCoroutineScope()
51+ var showBrokeDialog by remember { mutableStateOf(false ) }
52+
53+
4454 LaunchedEffect (Unit ) {
55+ val treePurchaseManager = TreePurchaseManager ()
56+ purchasedTrees = treePurchaseManager.loadAllPurchasedTrees()
57+
4558 val cacheManager = CacheManager ()
4659 cacheManager.readFile(" tree.json" )?.let {
4760 uiState = TreeUiState .Success (Json .decodeFromString(it))
@@ -58,11 +71,53 @@ fun GrowTreeBottomSheet(
5871 }
5972 }
6073
74+ if (showBrokeDialog) {
75+ Dialog (onDismissRequest = { showBrokeDialog = false }) {
76+ Card (
77+ shape = RoundedCornerShape (24 .dp),
78+ modifier = Modifier
79+ .fillMaxWidth()
80+ .padding(16 .dp)
81+ ) {
82+ Column (
83+ modifier = Modifier
84+ .padding(24 .dp)
85+ .fillMaxWidth(),
86+ horizontalAlignment = Alignment .CenterHorizontally ,
87+ verticalArrangement = Arrangement .spacedBy(16 .dp)
88+ ) {
89+ Text (
90+ text = " Too broke to buy this tree!" ,
91+ style = MaterialTheme .typography.headlineSmall,
92+ fontWeight = FontWeight .Bold ,
93+ textAlign = TextAlign .Center ,
94+ )
95+ Button (
96+ onClick = { showBrokeDialog = false },
97+ modifier = Modifier .fillMaxWidth(),
98+ shape = RoundedCornerShape (12 .dp),
99+ colors = ButtonDefaults .buttonColors(
100+ containerColor = MaterialTheme .colorScheme.primary,
101+ contentColor = MaterialTheme .colorScheme.onPrimary
102+ )
103+ ) {
104+ Text (
105+ text = " Close" ,
106+ modifier = Modifier .padding(vertical = 6 .dp),
107+ style = MaterialTheme .typography.titleMedium
108+ )
109+ }
110+ }
111+
112+ }
113+ }
114+ }
115+
61116 ModalBottomSheet (
62117 onDismissRequest = onDismiss,
63118 sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true ),
64119 containerColor = MaterialTheme .colorScheme.surface,
65- tonalElevation = 0 .dp // Cleaner flat look
120+ tonalElevation = 0 .dp
66121 ) {
67122 AnimatedContent (
68123 targetState = selectedTree,
@@ -79,14 +134,33 @@ fun GrowTreeBottomSheet(
79134 TreeDetailView (
80135 tree = tree,
81136 onBack = { selectedTree = null },
82- onSelect = { onSelected(tree) }
137+ onSelect = { onAddToCanvas(tree) },
138+ isPurchased = purchasedTrees.contains(tree.id),
139+ onPurchased = {
140+ if (viewModel.coins.value >= tree.basePrice){
141+ val tempTree = purchasedTrees.toMutableList()
142+ tempTree.add(tree.id)
143+ purchasedTrees = tempTree.toList()
144+ coroutine.launch {
145+ val purchaseManager = TreePurchaseManager ()
146+ purchaseManager.addTree(tree.id)
147+ viewModel.useCoins(tree.basePrice)
148+ onAddToCanvas(tree)
149+ }
150+ }else {
151+ showBrokeDialog = true
152+ }
153+ }
83154 )
84155 } else {
85156 TreeGridView (
86157 uiState = uiState,
87- onTreeSelected = { onSelected(it) },
158+ onTreeSelected = {
159+ if (purchasedTrees.contains(it.id)) onAddToCanvas(it) else selectedTree = it
160+ },
88161 onTreeLongPress = { selectedTree = it },
89- onShowWitheredTrees
162+ onShowWitheredTrees = onShowWitheredTrees,
163+ purchasedTrees = purchasedTrees
90164 )
91165 }
92166 }
@@ -99,7 +173,8 @@ private fun TreeGridView(
99173 uiState : TreeUiState ,
100174 onTreeSelected : (TreeData ) -> Unit ,
101175 onTreeLongPress : (TreeData ) -> Unit ,
102- onShowWitheredTrees : () -> Unit
176+ onShowWitheredTrees : () -> Unit ,
177+ purchasedTrees : List <String >
103178) {
104179 Column (
105180 modifier = Modifier
@@ -146,7 +221,7 @@ private fun TreeGridView(
146221 items = uiState.trees.filter { it.isGrowable },
147222 key = { it.id }
148223 ) { tree ->
149- TreeGridItem (tree, onTreeSelected, onTreeLongPress)
224+ TreeGridItem (tree, onTreeSelected, onTreeLongPress,purchasedTrees.contains(tree.id) )
150225 }
151226 }
152227 }
@@ -158,7 +233,9 @@ private fun TreeGridView(
158233private fun TreeDetailView (
159234 tree : TreeData ,
160235 onBack : () -> Unit ,
161- onSelect : () -> Unit
236+ onSelect : () -> Unit ,
237+ isPurchased : Boolean ,
238+ onPurchased : ()-> Unit ,
162239) {
163240 Column (
164241 modifier = Modifier
@@ -171,9 +248,7 @@ private fun TreeDetailView(
171248 label = { Text (" Go Back" ) },
172249 )
173250
174- // Main Info
175251 Row (verticalAlignment = Alignment .CenterVertically , horizontalArrangement = Arrangement .spacedBy(16 .dp),) {
176- // Main Preview Image
177252 AsyncImage (
178253 model = " ${Constants .cdn} /images/${tree.id} _${tree.variants - 1 } _grid.png" ,
179254 contentDescription = null ,
@@ -197,6 +272,13 @@ private fun TreeDetailView(
197272 text = tree.description,
198273 style = MaterialTheme .typography.bodyMedium,
199274 )
275+ if (! isPurchased) {
276+ Text (
277+ text = " Price: ${tree.basePrice} " ,
278+ style = MaterialTheme .typography.bodyMedium,
279+ color = MaterialTheme .colorScheme.error,
280+ )
281+ }
200282
201283 Spacer (Modifier .height(24 .dp))
202284
@@ -214,14 +296,24 @@ private fun TreeDetailView(
214296
215297 Spacer (Modifier .height(32 .dp))
216298
217- // Action Button
218- Button (
219- onClick = onSelect,
220- modifier = Modifier .fillMaxWidth().height(50 .dp),
221- shape = RoundedCornerShape (12 .dp)
222- ) {
223- Text (" Select This Tree" )
299+ if (isPurchased) {
300+ Button (
301+ onClick = onSelect,
302+ modifier = Modifier .fillMaxWidth().height(50 .dp),
303+ shape = RoundedCornerShape (12 .dp)
304+ ) {
305+ Text (" Select This Tree" )
306+ }
307+ }else {
308+ Button (
309+ onClick = onPurchased,
310+ modifier = Modifier .fillMaxWidth().height(50 .dp),
311+ shape = RoundedCornerShape (12 .dp)
312+ ) {
313+ Text (" Buy Tree" )
314+ }
224315 }
316+
225317 }
226318}
227319
@@ -230,7 +322,8 @@ private fun TreeDetailView(
230322private fun TreeGridItem (
231323 tree : TreeData ,
232324 onClick : (TreeData ) -> Unit ,
233- onLongClick : (TreeData ) -> Unit
325+ onLongClick : (TreeData ) -> Unit ,
326+ isPurchased : Boolean
234327) {
235328 val haptic = LocalHapticFeedback .current
236329
@@ -251,7 +344,8 @@ private fun TreeGridItem(
251344 Box (
252345 modifier = Modifier
253346 .size(90 .dp)
254- .padding(8 .dp),
347+ .padding(8 .dp)
348+ .alpha(if (isPurchased) 1f else 0.3f ),
255349 contentAlignment = Alignment .Center
256350 ) {
257351 AsyncImage (
@@ -268,7 +362,8 @@ private fun TreeGridItem(
268362 text = tree.name,
269363 style = MaterialTheme .typography.labelMedium,
270364 textAlign = TextAlign .Center ,
271- maxLines = 1 ,
365+ minLines = 2 ,
366+ maxLines = 2 ,
272367 overflow = TextOverflow .Ellipsis
273368 )
274369 }
0 commit comments