11package com.flipcash.app.tokens.internal
22
3+ import androidx.compose.foundation.Image
34import androidx.compose.foundation.layout.Arrangement
45import androidx.compose.foundation.layout.Box
56import androidx.compose.foundation.layout.PaddingValues
67import androidx.compose.foundation.layout.Row
78import androidx.compose.foundation.layout.Spacer
9+ import androidx.compose.foundation.layout.aspectRatio
810import androidx.compose.foundation.layout.fillMaxSize
911import androidx.compose.foundation.layout.fillMaxWidth
1012import androidx.compose.foundation.layout.height
@@ -21,6 +23,9 @@ import androidx.compose.runtime.remember
2123import androidx.compose.runtime.setValue
2224import androidx.compose.ui.Alignment
2325import androidx.compose.ui.Modifier
26+ import androidx.compose.ui.graphics.Color
27+ import androidx.compose.ui.graphics.StrokeCap
28+ import androidx.compose.ui.res.painterResource
2429import androidx.compose.ui.res.stringResource
2530import androidx.compose.ui.unit.dp
2631import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -39,6 +44,7 @@ import com.getcode.ui.core.measured
3944import com.getcode.ui.core.verticalScrollStateGradient
4045import com.getcode.ui.theme.ButtonState
4146import com.getcode.ui.theme.CodeButton
47+ import com.getcode.ui.theme.CodeCircularProgressIndicator
4248import com.getcode.ui.theme.CodeScaffold
4349import com.getcode.ui.utils.calculateEndPadding
4450import com.getcode.ui.utils.calculateStartPadding
@@ -79,93 +85,138 @@ private fun TokenInfoScreen(
7985 .sheetResignmentBehavior(listState),
8086 state = listState,
8187 ) {
82- item {
83- TokenBalance (
84- modifier = Modifier
85- .fillMaxWidth()
86- .padding(horizontal = CodeTheme .dimens.inset),
87- balance = state.balance.nativeAmount,
88- appreciation = state.appreciation?.nativeAmount?.takeIf { state.showAppreciation },
89- onClick = {
90- dispatch(
91- TokenInfoViewModel .Event .OpenScreen (
92- AppRoute .Main .RegionSelection (kind = RegionSelectionKind .Balance )
93- )
94- )
88+ when (val loadable = state.token) {
89+ is Loadable .Loading -> {
90+ item {
91+ Box (modifier = Modifier .fillParentMaxSize()) {
92+ Box (
93+ modifier = Modifier
94+ .fillParentMaxSize(0.24f )
95+ .aspectRatio(1f )
96+ .align(Alignment .Center ),
97+ ) {
98+ CodeCircularProgressIndicator (
99+ modifier = Modifier
100+ .matchParentSize(),
101+ strokeWidth = CodeTheme .dimens.grid.x1,
102+ color = Color .White ,
103+ backgroundColor = Color .White .copy(0.30f ),
104+ strokeCap = StrokeCap .Butt ,
105+ )
106+ }
107+ }
95108 }
96- )
97- }
98-
99- if (! state.isCashReserve && state.showTransactionHistory) {
100- item {
101- CodeButton (
102- modifier = Modifier
103- .fillParentMaxWidth()
104- .padding(horizontal = CodeTheme .dimens.inset)
105- .padding(top = CodeTheme .dimens.grid.x5),
106- buttonState = ButtonState .Filled10 ,
107- text = stringResource(R .string.action_viewTransactionHistory),
108- ) {
109- dispatch(
110- TokenInfoViewModel .Event .OpenScreen (
111- AppRoute .Token .Transactions (state.token?.address!! )
112- )
109+ }
110+ is Loadable .Error -> {
111+ item {
112+ Box (modifier = Modifier .fillParentMaxSize()) {
113+ Box (
114+ modifier = Modifier
115+ .fillParentMaxSize(0.24f )
116+ .aspectRatio(1f )
117+ .align(Alignment .Center ),
118+ ) {
119+ Image (
120+ modifier = Modifier
121+ .matchParentSize(),
122+ painter = painterResource(R .drawable.ic_circle_exclamation_large),
123+ contentDescription = null ,
124+ )
125+ }
126+ }
127+ }
128+ }
129+ is Loadable .Loaded -> {
130+ item {
131+ TokenBalance (
132+ modifier = Modifier
133+ .fillMaxWidth()
134+ .padding(horizontal = CodeTheme .dimens.inset),
135+ balance = state.balance.nativeAmount,
136+ appreciation = state.appreciation?.nativeAmount?.takeIf { state.showAppreciation },
137+ onClick = {
138+ dispatch(
139+ TokenInfoViewModel .Event .OpenScreen (
140+ AppRoute .Main .RegionSelection (kind = RegionSelectionKind .Balance )
141+ )
142+ )
143+ }
113144 )
114145 }
115146
116- Divider (
117- modifier = Modifier .padding(
118- horizontal = CodeTheme .dimens.inset,
119- vertical = CodeTheme .dimens.grid.x5
120- ),
121- color = CodeTheme .colors.dividerVariant,
122- )
123- }
124- }
147+ if (! state.isCashReserve && state.showTransactionHistory) {
148+ item {
149+ CodeButton (
150+ modifier = Modifier
151+ .fillParentMaxWidth()
152+ .padding(horizontal = CodeTheme .dimens.inset)
153+ .padding(top = CodeTheme .dimens.grid.x5),
154+ buttonState = ButtonState .Filled10 ,
155+ text = stringResource(R .string.action_viewTransactionHistory),
156+ ) {
157+ dispatch(
158+ TokenInfoViewModel .Event .OpenScreen (
159+ AppRoute .Token .Transactions (loadable.data.address)
160+ )
161+ )
162+ }
125163
126- // currency info
127- item {
128- if (state.isCashReserve && state.cashReservesEnabled) {
129- Text (
130- modifier = Modifier
131- .fillParentMaxWidth()
132- .padding(horizontal = CodeTheme .dimens.inset),
133- text = state.token?.description.orEmpty(),
134- style = CodeTheme .typography.textMedium,
135- color = CodeTheme .colors.textSecondary,
136- )
137- } else {
138- TokenDetailsSection (
139- modifier = Modifier
140- .fillParentMaxWidth(),
141- state = state,
142- dispatch = dispatch
143- )
144- }
145- }
164+ Divider (
165+ modifier = Modifier .padding(
166+ horizontal = CodeTheme .dimens.inset,
167+ vertical = CodeTheme .dimens.grid.x5
168+ ),
169+ color = CodeTheme .colors.dividerVariant,
170+ )
171+ }
172+ }
146173
147- if (! state.isCashReserve) {
148- // market cap
149- state.marketCap?.let { mcap ->
150- val loadable = state.historicalMarketCapData[state.selectedPeriod] ? : Loadable .Loaded (emptyList())
174+ // currency info
151175 item {
152- MarketCapSection (
153- modifier = Modifier
154- .fillParentMaxWidth(),
155- contentPadding = PaddingValues (horizontal = CodeTheme .dimens.inset),
156- marketCap = mcap,
157- chartEnabled = state.marketCapChartEnabled,
158- selectedPeriod = state.selectedPeriod,
159- rawHistoricalData = loadable,
160- onPeriodSelected = {
161- dispatch(TokenInfoViewModel .Event .OnMarketCapPeriodSelected (it))
162- },
163- )
176+ if (state.isCashReserve && state.cashReservesEnabled) {
177+ Text (
178+ modifier = Modifier
179+ .fillParentMaxWidth()
180+ .padding(horizontal = CodeTheme .dimens.inset),
181+ text = loadable.data.description,
182+ style = CodeTheme .typography.textMedium,
183+ color = CodeTheme .colors.textSecondary,
184+ )
185+ } else {
186+ TokenDetailsSection (
187+ modifier = Modifier
188+ .fillParentMaxWidth(),
189+ state = state,
190+ dispatch = dispatch
191+ )
192+ }
193+ }
194+
195+ if (! state.isCashReserve) {
196+ // market cap
197+ state.marketCap?.let { mcap ->
198+ val loadable = state.historicalMarketCapData[state.selectedPeriod] ? : Loadable .Loaded (emptyList())
199+ item {
200+ MarketCapSection (
201+ modifier = Modifier
202+ .fillParentMaxWidth(),
203+ contentPadding = PaddingValues (horizontal = CodeTheme .dimens.inset),
204+ marketCap = mcap,
205+ chartEnabled = state.marketCapChartEnabled,
206+ selectedPeriod = state.selectedPeriod,
207+ rawHistoricalData = loadable,
208+ onPeriodSelected = {
209+ dispatch(TokenInfoViewModel .Event .OnMarketCapPeriodSelected (it))
210+ },
211+ )
212+ }
213+ }
164214 }
215+
216+ item { Spacer (Modifier .height(innerPadding.calculateBottomPadding())) }
165217 }
166218 }
167219
168- item { Spacer (Modifier .height(innerPadding.calculateBottomPadding())) }
169220 }
170221 }
171222 }
@@ -213,65 +264,71 @@ private fun BottomBarButtons(
213264 modifier : Modifier = Modifier ,
214265 dispatch : (TokenInfoViewModel .Event ) -> Unit
215266) {
216- Row (
217- modifier = modifier
218- .fillMaxWidth(),
219- verticalAlignment = Alignment .CenterVertically ,
220- horizontalArrangement = Arrangement .spacedBy(CodeTheme .dimens.grid.x2),
221- ) {
222- if (state.isCashReserve && state.cashReservesEnabled) {
223- CodeButton (
224- modifier = Modifier .weight(1f ),
225- buttonState = ButtonState .Filled ,
226- text = stringResource(R .string.action_withdraw),
267+ when (val loadable = state.token) {
268+ is Loadable .Error -> Unit
269+ is Loadable .Loaded -> {
270+ Row (
271+ modifier = modifier
272+ .fillMaxWidth(),
273+ verticalAlignment = Alignment .CenterVertically ,
274+ horizontalArrangement = Arrangement .spacedBy(CodeTheme .dimens.grid.x2),
227275 ) {
228- dispatch(
229- TokenInfoViewModel .Event .OpenScreen (
230- AppRoute .Transfers .Withdrawal .Amount (state.mint!! )
231- )
232- )
233- }
234- } else if (state.cashReservesEnabled) {
235- CodeButton (
236- modifier = Modifier .weight(1f ),
237- buttonState = ButtonState .Filled ,
238- text = stringResource(R .string.action_buy),
239- ) {
240- dispatch(TokenInfoViewModel .Event .OpenPurchaseMethods (forNeededFunds = isForNeededFunds))
241- }
276+ if (state.isCashReserve && state.cashReservesEnabled) {
277+ CodeButton (
278+ modifier = Modifier .weight(1f ),
279+ buttonState = ButtonState .Filled ,
280+ text = stringResource(R .string.action_withdraw),
281+ ) {
282+ dispatch(
283+ TokenInfoViewModel .Event .OpenScreen (
284+ AppRoute .Transfers .Withdrawal .Amount (loadable.data.address)
285+ )
286+ )
287+ }
288+ } else if (state.cashReservesEnabled) {
289+ CodeButton (
290+ modifier = Modifier .weight(1f ),
291+ buttonState = ButtonState .Filled ,
292+ text = stringResource(R .string.action_buy),
293+ ) {
294+ dispatch(TokenInfoViewModel .Event .OpenPurchaseMethods (forNeededFunds = isForNeededFunds))
295+ }
242296
243- if (state.canSell) {
244- CodeButton (
245- modifier = Modifier
246- .weight(1f ),
247- buttonState = ButtonState .Filled20 ,
248- text = stringResource(R .string.action_sell),
249- ) {
250- dispatch(
251- TokenInfoViewModel .Event .OpenScreen (
252- AppRoute .Token .SwapTransact (
253- purpose = TokenSwapPurpose .Sell (state.token!! .address),
297+ if (state.canSell) {
298+ CodeButton (
299+ modifier = Modifier
300+ .weight(1f ),
301+ buttonState = ButtonState .Filled20 ,
302+ text = stringResource(R .string.action_sell),
303+ ) {
304+ dispatch(
305+ TokenInfoViewModel .Event .OpenScreen (
306+ AppRoute .Token .SwapTransact (
307+ purpose = TokenSwapPurpose .Sell (loadable.data.address),
308+ )
309+ )
310+ )
311+ }
312+ }
313+ } else {
314+ CodeButton (
315+ modifier = Modifier
316+ .fillMaxWidth()
317+ .padding(horizontal = CodeTheme .dimens.inset)
318+ .padding(bottom = CodeTheme .dimens.grid.x3)
319+ .navigationBarsPadding(),
320+ buttonState = ButtonState .Filled ,
321+ text = stringResource(R .string.action_give),
322+ ) {
323+ dispatch(
324+ TokenInfoViewModel .Event .OpenScreen (
325+ AppRoute .Main .Give (mint = loadable.data.address)
254326 )
255327 )
256- )
328+ }
257329 }
258330 }
259- } else {
260- CodeButton (
261- modifier = Modifier
262- .fillMaxWidth()
263- .padding(horizontal = CodeTheme .dimens.inset)
264- .padding(bottom = CodeTheme .dimens.grid.x3)
265- .navigationBarsPadding(),
266- buttonState = ButtonState .Filled ,
267- text = stringResource(R .string.action_give),
268- ) {
269- dispatch(
270- TokenInfoViewModel .Event .OpenScreen (
271- AppRoute .Main .Give (mint = state.token?.address!! )
272- )
273- )
274- }
275331 }
332+ is Loadable .Loading -> Unit
276333 }
277334}
0 commit comments