From c5502282e4718f3f79f058f947e0de045ba2658b Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Fri, 20 Dec 2024 14:20:01 +0530 Subject: [PATCH 01/16] - My Trades UI (#132), Trading UI Dialogs (#131) --- .../ui/components/BackHandler.android.kt | 11 ++ .../composeResources/drawable/icon_info.png | Bin 337 -> 1123 bytes .../drawable/icon_warning.png | Bin 0 -> 960 bytes .../network/bisq/mobile/i18n/CommonStrings.kt | 4 + .../bisq/mobile/i18n/CommonStringsEn.kt | 4 + .../bisq/mobile/i18n/CommonStringsFr.kt | 4 + .../presentation/di/PresentationModule.kt | 2 +- .../presentation/ui/components/BackHandler.kt | 6 + .../ui/components/atoms/Button.kt | 10 +- .../ui/components/atoms/icons/Icons.kt | 7 +- .../ui/components/layout/ScrollScaffold.kt | 1 + .../ui/components/layout/StaticScaffold.kt | 1 + .../molecules/ConfirmationDialog.kt | 54 +++--- .../ui/components/molecules/Dialog.kt | 27 ++- .../ui/components/molecules/MyOfferCard.kt | 179 ++++++++++++++++++ .../ui/components/molecules/OfferCard.kt | 99 ++++++++-- .../ui/components/molecules/TopBar.kt | 61 ++++-- .../organisms/trades/CancelTradeDialog.kt | 81 ++++++++ ...{CloseTradeCard.kt => CloseTradeDialog.kt} | 111 +++++------ .../trades/MediationRequestDialog.kt | 58 ++++++ .../organisms/trades/TradeHeader.kt | 3 +- .../presentation/ui/theme/UIConstants.kt | 1 + .../settings/PaymentAccountSettingsScreen.kt | 2 +- .../ui/uicases/trades/MyTradesPresenter.kt | 37 ++-- .../ui/uicases/trades/MyTradesScreen.kt | 33 +++- .../ui/uicases/trades/TradeFlowPresenter.kt | 16 ++ .../ui/uicases/trades/TradeFlowScreen.kt | 55 ++++-- .../ui/components/BackHandler.ios.kt | 8 + 28 files changed, 713 insertions(+), 162 deletions(-) create mode 100644 shared/presentation/src/androidMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.android.kt create mode 100644 shared/presentation/src/commonMain/composeResources/drawable/icon_warning.png create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.kt create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CancelTradeDialog.kt rename shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/{CloseTradeCard.kt => CloseTradeDialog.kt} (78%) create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/MediationRequestDialog.kt create mode 100644 shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt diff --git a/shared/presentation/src/androidMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.android.kt b/shared/presentation/src/androidMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.android.kt new file mode 100644 index 00000000..43e1b411 --- /dev/null +++ b/shared/presentation/src/androidMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.android.kt @@ -0,0 +1,11 @@ +package network.bisq.mobile.presentation.ui.components + +import androidx.activity.compose.BackHandler as AndroidBackHandler +import androidx.compose.runtime.Composable + +@Composable +actual fun BackHandler(onBackPressed: () -> Unit) { + AndroidBackHandler { + onBackPressed() + } +} diff --git a/shared/presentation/src/commonMain/composeResources/drawable/icon_info.png b/shared/presentation/src/commonMain/composeResources/drawable/icon_info.png index 6c304de86505db97064e25159ac9e59795dcdc0f..9bd7d0d3b7161a91e1b45f289f5a2400e8e1da88 100644 GIT binary patch literal 1123 zcmV-p1f2VcP)42%g?!a;daVm&38J~YtPTmtGHdm#ouLp5&cS~qF!EJ6z+di ztJUt-)>ck9>;x=&9}?Y+G{B?VDP05X1mf4`60mXrVp za#2)}U;$1}PMUCqSi&`)2U?`Py}f-A@~0pHj*pMONVeAL=ii{oYq(TzX=zC{8jU_* z&|-IYcM*Jl6;};IA0%4=ot>SX&*BL$0m#6^!^0&sUvs=xxDMv$=Pw2f`{3~KunuA9 zhLQaais;SF&8_>a=OqB#<_65KTEkqt4Q+K~1VE5j3zB3E0S(H9yk#;^a4oLMwXIhzC~#<|%d|j-R#e%{d(iA7zTRiW zL#730W@b_W7Q#FB0MrD6wr-AL;n0nSvBOju zA+>r3x~9>#hFi>puK7*@wDwIXEF4Q1OoHC&mC%_@nPaemGZvfz*!iA2q=ciPndsAc z5{?7wx#^me3SwPVUKvAuXyl!Y8M@xO6~mG`2D|3Glm#%UWGM`aYDJcNvew{x1U?kq$ z-25tmAZ^5fIh0DJE(;_kg;ba(z^ZJ9YG<8P?j08pI|-5cGG^#*&{UkV>mVX4je1pr{}Xnj&nDkF&ozh^&fa*Uyx!CS z(~3$0fQmTP4f5p9HPLW8BYosE1Yy+}Nf@}n9V{*`c8a#GL}{N{AxuqwK3YL6L^?SC perDAdE8W*mP_DvkiYcZD$8T9n4ZCVE_5T0>002ovPDHLkV1i-b{Qdv{ literal 337 zcmV-X0j~auP)!O4R>?NFYvvZug)7)pvIt^qPsusB z;Hr{UaQ3N^7Kj3`lD~!0=nBfDO8%4tLhNNJd0e^->d4&ET&U88C3ixZp@x+?mi#I0 zYhZ#qm8rP3$wSizi~^N0)LB;=3B$ZX!VH>Jz1;cQaTY9R*@vjs&@z zz=5nCU{|d-{HG(IwRV;~4D+3kq0+U@#?RZZlzjvkJ}Q*1L-Ojk6k_UVWG+x)nZc&++^{ZcLemDTl^oDx6GM}yNP3itNGVpIeSUF*3aSr?f|Ob=v06R?hS-EWKAP&EF;?fYkxjyCwuDMK zP#T+sCrm}b!|z5ZtQtEIVH17z25d@Wj@&uYQMf1*1@j10#b%KrtR@F^DXbbfV1vyf z#aPu;t7Ze*ECL4Dw2}_1gc(Jl&;es?S}2Sp!w1FOj<21o;s}^y(@Jqf=TNR)G@x@G zu*7CEC8$x43Rul_z#5xTN{F^1J&c?VvC1%$jU1~v%g;vEA0akbb!^5dF-2*KsVpjSb>E&nYt)3JCr`2Z8dcgb~#aLZCu!U+f zIRRA~{3cl4M8I{mSz#W~>NxPBR;v+KL#@X^D)$+>J0(w!I6?;sg_iL<*C+yUz2Qj> z_T=V6rK{EEDvjK|Uf-hfCeZ8@0vmxnzI6RbsI1~oR(+*1Sf|jY7Gh*3=Na!n?tJbT z{;O`a*6Y>ICWUm<_kM~d=ccs-(exdhV!xfB2x@1^v`&{2BIkZJI;ew}0_+6)AsVJQ i&yrnK#0MSpkn|6Fw3Qu5P{GUq0000 Unit) \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/Button.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/Button.kt index 5a650444..17b7e25a 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/Button.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/Button.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants enum class BisqButtonType { Default, @@ -31,10 +32,13 @@ enum class BisqButtonType { @Composable fun BisqButton( text: String? = "Button", - onClick: () -> Unit, + onClick: (() -> Unit)? = null, color: Color = BisqTheme.colors.light1, backgroundColor: Color = BisqTheme.colors.primary, - padding: PaddingValues = PaddingValues(horizontal = 48.dp, vertical = 4.dp), + padding: PaddingValues = PaddingValues( + horizontal = BisqUIConstants.ScreenPadding4X, + vertical = BisqUIConstants.ScreenPaddingHalf + ), iconOnly: (@Composable () -> Unit)? = null, leftIcon: (@Composable () -> Unit)? = null, rightIcon: (@Composable () -> Unit)? = null, @@ -64,7 +68,7 @@ fun BisqButton( val finalContentColor = color Button( - onClick = { onClick() }, + onClick = { onClick?.invoke() }, contentPadding = if (iconOnly != null) PaddingValues(horizontal = 0.dp, vertical = 0.dp) else padding, colors = ButtonColors( containerColor = finalBackgroundColor, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt index 755e21f0..e908c6de 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt @@ -119,4 +119,9 @@ fun UserIcon(platformImage: PlatformImage?, modifier: Modifier = Modifier) { val painter = rememberPlatformImagePainter(platformImage) Image(painter = painter, contentDescription = "User icon", modifier = modifier) } -} \ No newline at end of file +} + +//@Composable +//fun WarningIcon(modifier: Modifier = Modifier.size(36.dp)) { +// Image(painterResource(Res.drawable.icon_warning), "Warning icon", modifier = modifier) +//} diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt index 64a64ac4..01098b69 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.unit.dp import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants +// FinalTODO: Merge StaticScaffold and ScrollScaffold @Composable fun BisqScrollScaffold( padding: PaddingValues = PaddingValues( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt index d98eba62..ac195ae3 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.Modifier import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants +// FinalTODO: Merge StaticScaffold and ScrollScaffold @Composable fun BisqStaticScaffold( padding: PaddingValues = PaddingValues( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt index a94f63a0..4c14ef65 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt @@ -16,43 +16,43 @@ import network.bisq.mobile.presentation.ui.theme.BisqUIConstants fun ConfirmationDialog( title: String = "", message: String = "Are you sure?", + subMessage: String = "", confirmButtonText: String = "Yes", cancelButtonText: String = "No", onConfirm: () -> Unit, - onDismissRequest: () -> Unit, + onDismiss: () -> Unit, ) { BisqDialog { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 24.dp, horizontal = 20.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(20.dp) - ) { - BisqText.h6Regular( - text = message, + BisqText.h6Regular( + text = message, + color = BisqTheme.colors.light1, + modifier = Modifier.padding(vertical = 12.dp) + ) + if (subMessage.isNotEmpty()) { + BisqText.baseRegular( + text = subMessage, color = BisqTheme.colors.light1, modifier = Modifier.padding(vertical = 12.dp) ) - Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { - BisqButton( - text = cancelButtonText, - backgroundColor = BisqTheme.colors.dark5, - onClick = { onDismissRequest() }, - padding = PaddingValues( - horizontal = BisqUIConstants.ScreenPadding4X, - vertical = BisqUIConstants.ScreenPaddingHalf - ) + } + Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { + BisqButton( + text = cancelButtonText, + backgroundColor = BisqTheme.colors.dark5, + onClick = onDismiss, + padding = PaddingValues( + horizontal = BisqUIConstants.ScreenPadding4X, + vertical = BisqUIConstants.ScreenPaddingHalf ) - BisqButton( - text = confirmButtonText, - onClick = { onConfirm() }, - padding = PaddingValues( - horizontal = BisqUIConstants.ScreenPadding4X, - vertical = BisqUIConstants.ScreenPaddingHalf - ) + ) + BisqButton( + text = confirmButtonText, + onClick = onConfirm, + padding = PaddingValues( + horizontal = BisqUIConstants.ScreenPadding4X, + vertical = BisqUIConstants.ScreenPaddingHalf ) - } + ) } } } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/Dialog.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/Dialog.kt index 5edb4211..69a823cb 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/Dialog.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/Dialog.kt @@ -1,11 +1,9 @@ package network.bisq.mobile.presentation.ui.components.molecules -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Card import androidx.compose.material3.CardColors import androidx.compose.runtime.Composable @@ -16,17 +14,22 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants @Composable fun BisqDialog( onDismissRequest: () -> Unit = {}, + horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, content: @Composable ColumnScope.() -> Unit = {} ) { - Dialog(onDismissRequest = onDismissRequest, properties = DialogProperties(dismissOnClickOutside = true)) { + Dialog( + onDismissRequest = onDismissRequest, + properties = DialogProperties(dismissOnClickOutside = true) + ) { Box( modifier = Modifier .fillMaxSize() - .padding(top = 86.dp) + .padding(top = BisqUIConstants.ScreenPadding5X) ) { Card( modifier = Modifier @@ -40,7 +43,15 @@ fun BisqDialog( ), shape = RoundedCornerShape(16.dp), ) { - content() + // TODO: When content is too long, footer buttons will be hidden at bottom now. + // Dialog should have Header, Footer with scrollable only for content + Column( + modifier = Modifier.padding(BisqUIConstants.ScreenPadding2X).verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(BisqUIConstants.ScreenPadding), + horizontalAlignment = horizontalAlignment, + ) { + content() + } } } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt new file mode 100644 index 00000000..16fa8eed --- /dev/null +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt @@ -0,0 +1,179 @@ +package network.bisq.mobile.presentation.ui.components.molecules + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO +import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.components.atoms.icons.LanguageIcon +import cafe.adriel.lyricist.LocalStrings +import network.bisq.mobile.domain.data.model.MockOffer +import network.bisq.mobile.presentation.ui.components.atoms.* +import network.bisq.mobile.presentation.ui.components.atoms.icons.ChatIcon +import network.bisq.mobile.presentation.ui.components.atoms.icons.LanguageIcon +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqVDivider +import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants + +@Composable +fun MyOfferCard( + offerListItem: MockOffer, + myTrade: Boolean = false, + onClick: () -> Unit, + onChatClick: () -> Unit, +) { + val strings = LocalStrings.current.common + + Column( + modifier = Modifier + .fillMaxWidth() + .clip(shape = RoundedCornerShape(8.dp)) + .background(color = BisqTheme.colors.dark5) + ) { + Row( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .padding(BisqUIConstants.ScreenPadding) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onClick + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Column( + verticalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier.weight(3f), + ) { + BisqText.baseRegular("TODO: User profile") + BisqText.baseRegular("TODO: Payment methods") + /* + UserProfile(offerListItem) + PaymentMethods(offerListItem) + */ + } + Column( + horizontalAlignment = Alignment.End, + verticalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.weight(2f) + ) { + // Len: 13 - "300 - 600 USD" + // Len: 17 - "3,000 - 6,000 XYZ" + // Len: 23 - "150,640 - 1,200,312 CRC" + //if (offerListItem.formattedQuoteAmount.length < 18) { + BisqText.baseRegular( + text = "mockOffer.formattedQuoteAmount", + color = BisqTheme.colors.primary + ) + /* } else { + BisqText.smallRegular( + text = offerListItem.formattedQuoteAmount, + color = BisqTheme.colors.primary + ) + }*/ + BisqGap.H1() + Row { + BisqText.smallRegular( + text = "@ ", + color = BisqTheme.colors.grey2 + ) + BisqText.smallRegular( + text = "mockOffer.formattedPriceSpec", + color = BisqTheme.colors.light1 + ) + } + Row(verticalAlignment = Alignment.CenterVertically) { + LanguageIcon() + BisqText.smallRegular( + text = " : ", + color = BisqTheme.colors.grey2 + ) + BisqText.smallRegular( + text = "mockOffer.bisqEasyOffer.supportedLanguageCodes.joinToString().uppercase()", + color = BisqTheme.colors.light1 + ) +// Row(verticalAlignment = Alignment.CenterVertically) { +// LanguageIcon() +// BisqText.largeRegular( +// text = ": ${offerListItem. }", +// color = BisqTheme.colors.grey1 +// ) +// } + BisqGap.H1() + // Len: 13 - "300 - 600 USD" + // Len: 17 - "3,000 - 6,000 XYZ" + // Len: 23 - "150,640 - 1,200,312 CRC" + /* + if (offerListItem.formattedQuoteAmount.length < 18) { + BisqText.baseRegular( + text = offerListItem.formattedQuoteAmount, + color = BisqTheme.colors.light1 + ) + } else { + BisqText.smallRegular( + text = offerListItem.formattedQuoteAmount, + color = BisqTheme.colors.light1 + ) + } + */ + } + } + /* + if (!myTrade) { + BisqVDivider() + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.width(36.dp).height(108.dp).background(color = BisqTheme.colors.dark4) + ) { + IconButton(onClick = onChatClick) { + ChatIcon(modifier = Modifier.size(24.dp)) + } + } + } + */ + } + + if (myTrade) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding( + start = BisqUIConstants.ScreenPadding, + end = BisqUIConstants.ScreenPadding, + top = 0.dp, + bottom = BisqUIConstants.ScreenPadding, + ) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onClick + ), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + BisqText.baseRegular("3 days ago", color = BisqTheme.colors.light1) + BisqButton( + text = strings.common_buy, + disabled = true, + padding = PaddingValues( + horizontal = BisqUIConstants.ScreenPadding2X, + vertical = BisqUIConstants.ScreenPaddingHalf + ), + backgroundColor = BisqTheme.colors.warning + ) + } + } + } +} \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt index d6c63252..a97e355a 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt @@ -3,11 +3,7 @@ package network.bisq.mobile.presentation.ui.components.molecules import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -18,16 +14,25 @@ import androidx.compose.ui.unit.dp import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.icons.LanguageIcon +import cafe.adriel.lyricist.LocalStrings +import network.bisq.mobile.presentation.ui.components.atoms.* +import network.bisq.mobile.presentation.ui.components.atoms.icons.ChatIcon +import network.bisq.mobile.presentation.ui.components.atoms.icons.LanguageIcon import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqVDivider import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants @Composable fun OfferCard( offerListItem: OfferListItemVO, + myTrade: Boolean = false, onClick: () -> Unit, onChatClick: () -> Unit, ) { - Row( + val strings = LocalStrings.current.common + + Column( modifier = Modifier .fillMaxWidth() .clip(shape = RoundedCornerShape(8.dp)) @@ -35,9 +40,8 @@ fun OfferCard( ) { Row( modifier = Modifier - .weight(1f) .fillMaxWidth() - .padding(12.dp) + .padding(BisqUIConstants.ScreenPadding) .clickable( interactionSource = remember { MutableInteractionSource() }, indication = null, @@ -48,7 +52,7 @@ fun OfferCard( ) { Column( verticalArrangement = Arrangement.spacedBy(12.dp), - modifier = Modifier.weight(2f) + modifier = Modifier.weight(3f), ) { UserProfile(offerListItem) PaymentMethods(offerListItem) @@ -93,18 +97,75 @@ fun OfferCard( text = offerListItem.bisqEasyOffer.supportedLanguageCodes.joinToString(", ").uppercase(), color = BisqTheme.colors.light1 ) +// Row(verticalAlignment = Alignment.CenterVertically) { +// LanguageIcon() +// BisqText.largeRegular( +// text = ": ${offerListItem. }", +// color = BisqTheme.colors.grey1 +// ) +// } + BisqGap.H1() + // Len: 13 - "300 - 600 USD" + // Len: 17 - "3,000 - 6,000 XYZ" + // Len: 23 - "150,640 - 1,200,312 CRC" + if (offerListItem.formattedQuoteAmount.length < 18) { + BisqText.baseRegular( + text = offerListItem.formattedQuoteAmount, + color = BisqTheme.colors.light1 + ) + } else { + BisqText.smallRegular( + text = offerListItem.formattedQuoteAmount, + color = BisqTheme.colors.light1 + ) + } } } + /* + if (!myTrade) { + BisqVDivider() + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.width(36.dp).height(108.dp).background(color = BisqTheme.colors.dark4) + ) { + IconButton(onClick = onChatClick) { + ChatIcon(modifier = Modifier.size(24.dp)) + } + } + } + */ + } + + if (myTrade) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding( + start = BisqUIConstants.ScreenPadding, + end = BisqUIConstants.ScreenPadding, + top = 0.dp, + bottom = BisqUIConstants.ScreenPadding, + ) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onClick + ), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + BisqText.baseRegular("3 days ago", color = BisqTheme.colors.light1) + BisqButton( + text = strings.common_buy, + disabled = true, + padding = PaddingValues( + horizontal = BisqUIConstants.ScreenPadding2X, + vertical = BisqUIConstants.ScreenPaddingHalf + ), + backgroundColor = BisqTheme.colors.warning + ) + } } - /* BisqVDivider() - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.width(36.dp).height(108.dp).background(color = BisqTheme.colors.dark4) - ) { - IconButton(onClick = onChatClick) { - ChatIcon(modifier = Modifier.size(24.dp)) - } - }*/ } } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt index 58ecd2c6..7da733ab 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt @@ -19,20 +19,23 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.draw.alpha import androidx.navigation.compose.currentBackStackEntryAsState +import network.bisq.mobile.presentation.ui.components.BackHandler import network.bisq.mobile.presentation.ui.components.atoms.animations.ShineOverlay import network.bisq.mobile.presentation.ui.components.atoms.icons.BisqLogoSmall import network.bisq.mobile.presentation.ui.components.atoms.icons.UserIcon import network.bisq.mobile.presentation.ui.navigation.Routes import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.koin.compose.koinInject -import org.koin.core.qualifier.named - -interface ITopBarPresenter: ViewPresenter { - fun onAvatarClicked() +interface ITopBarPresenter : ViewPresenter { val uniqueAvatar: StateFlow + fun onAvatarClicked() } @OptIn(ExperimentalMaterial3Api::class) @@ -41,6 +44,7 @@ fun TopBar( title: String = "", isHome: Boolean = false, customBackButton: @Composable (() -> Unit)? = null, + backConfirmation: Boolean = false, isFlowScreen: Boolean = false, stepText: String = "" ) { @@ -49,6 +53,7 @@ fun TopBar( val tabNavController: NavHostController = presenter.getRootTabNavController() val interactionEnabled = presenter.isInteractive.collectAsState().value + var showBackConfirmationDialog by remember { mutableStateOf(false) } val currentTab = tabNavController.currentBackStackEntryAsState().value?.destination?.route @@ -57,7 +62,13 @@ fun TopBar( val defaultBackButton: @Composable () -> Unit = { IconButton(onClick = { if (navController.previousBackStackEntry != null) { - presenter.goBack() + if (backConfirmation) { + if (!showBackConfirmationDialog) { + showBackConfirmationDialog = true + } + } else { + presenter.goBack() + } } }) { Icon( @@ -106,24 +117,44 @@ fun TopBar( }, actions = { Row( - modifier = Modifier.padding(top = if (isFlowScreen) 15.dp else 0.dp, end = 16.dp), + modifier = Modifier.padding(top = if (isFlowScreen) 15.dp else 0.dp, end = 16.dp), verticalAlignment = Alignment.CenterVertically ) { // TODO implement full feature after MVP // BellIcon() Spacer(modifier = Modifier.width(12.dp)) ShineOverlay { - UserIcon(presenter.uniqueAvatar.value, - modifier = Modifier.size(30.dp) -// .fillMaxSize() - .alpha(if (currentTab == Routes.TabSettings.name) 0.5f else 1.0f) - .clickable { - if (currentTab != Routes.TabSettings.name && interactionEnabled) { - presenter.onAvatarClicked() - } - }) + UserIcon( + presenter.uniqueAvatar.value, + modifier = Modifier.size(30.dp) + .alpha(if (currentTab == Routes.TabSettings.name) 0.5f else 1.0f) + .clickable { + if (currentTab != Routes.TabSettings.name) { + navController.navigate(Routes.UserProfileSettings.name) + } + }) } } }, ) + + if (backConfirmation) { + BackHandler( onBackPressed = { + showBackConfirmationDialog = true + }) + } + + if (showBackConfirmationDialog) { + ConfirmationDialog( + message = "Are you sure want to exit the Trade?", + subMessage = "You can resume later", + onConfirm = { + showBackConfirmationDialog = false + presenter.goBack() + }, + onDismiss = { + showBackConfirmationDialog = false + } + ) + } } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CancelTradeDialog.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CancelTradeDialog.kt new file mode 100644 index 00000000..86dfb125 --- /dev/null +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CancelTradeDialog.kt @@ -0,0 +1,81 @@ +package network.bisq.mobile.presentation.ui.components.organisms.trades + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.unit.dp +import cafe.adriel.lyricist.LocalStrings +import network.bisq.mobile.presentation.ui.components.atoms.BisqButton +import network.bisq.mobile.presentation.ui.components.atoms.BisqText +// import network.bisq.mobile.presentation.ui.components.atoms.icons.WarningIcon +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap +import network.bisq.mobile.presentation.ui.components.molecules.BisqDialog +import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants + +@Composable +fun CancelTradeDialog( + onCancelConfirm: () -> Unit, + onDismiss: () -> Unit +) { + val strings = LocalStrings.current.bisqEasy + val stringsApplication = LocalStrings.current.application + val stringsCommon = LocalStrings.current.common + + val isBuyer: Boolean = true + + // TODO: Use this if trade steps is not started yet: bisqEasy_openTrades_rejectTrade_warning + val warningText1 = if (isBuyer) + strings.bisqEasy_openTrades_cancelTrade_warning_buyer + else + strings.bisqEasy_openTrades_cancelTrade_warning_seller + + val warningText2 = strings.bisqEasy_openTrades_cancelTrade_warning_part2 + + BisqDialog(horizontalAlignment = Alignment.Start) { + Row( + modifier = Modifier.padding(bottom = BisqUIConstants.ScreenPadding), + verticalAlignment = Alignment.CenterVertically + ) { + // WarningIcon() + BisqGap.H1() + BisqText.h6Medium( + text = stringsApplication.popup_headline_warning, + color = BisqTheme.colors.warning + ) + } + + BisqText.baseRegular(text = warningText1 + warningText2) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + BisqButton( + text = stringsCommon.common_no, + onClick = onCancelConfirm, + padding = PaddingValues(horizontal = BisqUIConstants.ScreenPadding, vertical = 8.dp), + backgroundColor = BisqTheme.colors.dark5 + ) + BisqGap.H1() + BisqButton( + text = stringsCommon.common_yes, + onClick = onDismiss, + padding = PaddingValues(horizontal = BisqUIConstants.ScreenPadding, vertical = 8.dp) + ) + } + } +} \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CloseTradeCard.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CloseTradeDialog.kt similarity index 78% rename from shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CloseTradeCard.kt rename to shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CloseTradeDialog.kt index 1f544442..f47a69e4 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CloseTradeCard.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/CloseTradeDialog.kt @@ -1,55 +1,58 @@ -package network.bisq.mobile.presentation.ui.components.organisms.trades - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.padding -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import cafe.adriel.lyricist.LocalStrings -import network.bisq.mobile.presentation.ui.components.atoms.BisqButton -import network.bisq.mobile.presentation.ui.components.atoms.BisqText -import network.bisq.mobile.presentation.ui.theme.BisqTheme - -@Composable -fun CloseTradeCard( - onDismissRequest: () -> Unit, - onConfirm: () -> Unit -) { - val strings = LocalStrings.current.bisqEasyTradeState - val stringsBisqEasy = LocalStrings.current.bisqEasy - val stringsCommon = LocalStrings.current.common - - Column( - modifier = Modifier.padding(24.dp), - verticalArrangement = Arrangement.spacedBy(24.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - - BisqText.h4Regular(text = strings.bisqEasy_tradeState_phase4) - - BisqText.baseRegular( - text = stringsBisqEasy.bisqEasy_openTrades_closeTrade_warning_completed, - color = BisqTheme.colors.grey1, - textAlign = TextAlign.Center - ) - - Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { - BisqButton( - text = stringsCommon.buttons_cancel, - backgroundColor = BisqTheme.colors.dark5, - onClick = onDismissRequest, - padding = PaddingValues(horizontal = 20.dp, vertical = 8.dp) - ) - BisqButton( - text = stringsBisqEasy.bisqEasy_openTrades_confirmCloseTrade, - onClick = onConfirm, - padding = PaddingValues(horizontal = 12.dp, vertical = 8.dp) - ) - } - } +package network.bisq.mobile.presentation.ui.components.organisms.trades + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import cafe.adriel.lyricist.LocalStrings +import network.bisq.mobile.presentation.ui.components.atoms.BisqButton +import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap +import network.bisq.mobile.presentation.ui.components.molecules.BisqDialog +import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants + +@Composable +fun CloseTradeDialog( + onDismissRequest: () -> Unit, + onConfirm: () -> Unit +) { + val strings = LocalStrings.current.bisqEasyTradeState + val stringsBisqEasy = LocalStrings.current.bisqEasy + val stringsCommon = LocalStrings.current.common + + BisqDialog { + + BisqText.h4Regular( + text = strings.bisqEasy_tradeState_phase4, + modifier = Modifier.padding(bottom= BisqUIConstants.ScreenPadding) + ) + + BisqText.baseRegular( + text = stringsBisqEasy.bisqEasy_openTrades_closeTrade_warning_completed, + color = BisqTheme.colors.grey1, + textAlign = TextAlign.Center + ) + + Row { + BisqButton( + text = stringsCommon.buttons_cancel, + backgroundColor = BisqTheme.colors.dark5, + onClick = onDismissRequest, + padding = PaddingValues(horizontal = 20.dp, vertical = 8.dp) + ) + BisqGap.H1() + BisqButton( + text = stringsBisqEasy.bisqEasy_openTrades_confirmCloseTrade, + onClick = onConfirm, + padding = PaddingValues(horizontal = 12.dp, vertical = 8.dp) + ) + } + } } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/MediationRequestDialog.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/MediationRequestDialog.kt new file mode 100644 index 00000000..eb8cebd6 --- /dev/null +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/MediationRequestDialog.kt @@ -0,0 +1,58 @@ +package network.bisq.mobile.presentation.ui.components.organisms.trades + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import network.bisq.mobile.presentation.ui.components.atoms.BisqButton +import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.components.atoms.icons.InfoIcon +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap +import network.bisq.mobile.presentation.ui.components.molecules.BisqDialog +import network.bisq.mobile.presentation.ui.theme.BisqTheme + +@Composable +fun MediationRequestDialog( + onConfirm: () -> Unit, + onDismiss: () -> Unit, +) { + BisqDialog { + Row { + InfoIcon() + BisqGap.H1() + BisqText.h6Regular( + text = "Request mediation", + color = BisqTheme.colors.primary + ) + } + Column { + BisqText.baseRegular( + text = "If you have problems which you cannot resolve with your trade partner your can request assistance from a mediator.", + textAlign = TextAlign.Center + ) + BisqGap.V1() + BisqText.smallRegular( + text = "Please do not request mediation for general questions. In the support section there are chat rooms where you can get general advice and help.", + color = BisqTheme.colors.grey1, + textAlign = TextAlign.Center + ) + } + Row { + BisqButton( + text = "Cancel", + backgroundColor = BisqTheme.colors.dark5, + onClick = onDismiss, + padding = PaddingValues(horizontal = 42.dp, vertical = 8.dp) + ) + BisqGap.H1() + BisqButton( + text = "Open mediation", + backgroundColor = BisqTheme.colors.primary, + onClick = onConfirm, + padding = PaddingValues(horizontal = 18.dp, vertical = 8.dp) + ) + } + } +} \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeHeader.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeHeader.kt index b9c56ce4..3c6e853e 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeHeader.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeHeader.kt @@ -44,6 +44,7 @@ import network.bisq.mobile.presentation.ui.theme.BisqTheme @Composable fun TradeHeader( offer: OfferListItemVO, + onCancel: () -> Unit, ) { val strings = LocalStrings.current.bisqEasyTradeState val stringsBisqEasy = LocalStrings.current.bisqEasy @@ -148,7 +149,7 @@ fun TradeHeader( BisqButton( text = stringsBisqEasy.bisqEasy_openTrades_cancelTrade, color = BisqTheme.colors.grey1, - onClick = {}, + onClick = onCancel, backgroundColor = Color.Transparent, padding = PaddingValues(horizontal = 70.dp, vertical = 6.dp) ) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/theme/UIConstants.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/theme/UIConstants.kt index 778de33b..e1756ec7 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/theme/UIConstants.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/theme/UIConstants.kt @@ -2,6 +2,7 @@ package network.bisq.mobile.presentation.ui.theme import androidx.compose.ui.unit.dp +// FinalTODO: Refactor and remove the prefix 'ScreenPadding' object BisqUIConstants { val ScreenPaddingQuarter = 3.dp val ScreenPaddingHalf = 6.dp diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/settings/PaymentAccountSettingsScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/settings/PaymentAccountSettingsScreen.kt index 4837197b..2fd5d999 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/settings/PaymentAccountSettingsScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/settings/PaymentAccountSettingsScreen.kt @@ -151,7 +151,7 @@ fun PaymentAccountSettingsScreen() { accountDescription = presenter.selectedAccount.value.description showConfirmationDialog = false }, - onDismissRequest = { + onDismiss = { showConfirmationDialog = false } ) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt index b0449f2a..217b3f95 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt @@ -1,5 +1,6 @@ package network.bisq.mobile.presentation.ui.uicases.trades +import androidx.compose.runtime.mutableStateOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -8,13 +9,16 @@ import kotlinx.coroutines.launch import network.bisq.mobile.domain.data.BackgroundDispatcher import network.bisq.mobile.domain.data.model.MockOffer import network.bisq.mobile.domain.data.repository.MyTradesRepository +import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes class MyTradesPresenter( mainPresenter: MainPresenter, - private val myTradesRepository: MyTradesRepository + private val offerbookServiceFacade: OfferbookServiceFacade, + // private val myTradesRepository: MyTradesRepository, ) : BasePresenter(mainPresenter), IMyTrades { private val _myTrades = MutableStateFlow>(emptyList()) @@ -33,17 +37,28 @@ class MyTradesPresenter( } } + + override fun createOffer() { + log.i { "Goto create offer" } + rootNavigator.navigate(Routes.CreateOfferDirection.name) + } + + override fun gotoTradeScreen(offer: MockOffer) { + log.i { "Goto trade screen" } + rootNavigator.navigate(Routes.TradeFlow.name) + } + private fun refresh() { - CoroutineScope(BackgroundDispatcher).launch { - try { - delay(1000) // TODO: To simulate loading. Yet to be handled - val trades = myTradesRepository.fetch() - _myTrades.value = trades?.trades ?: emptyList() - } catch (e: Exception) { - // Handle errors - println("Error: ${e.message}") - } - } +// CoroutineScope(BackgroundDispatcher).launch { +// try { +// delay(1000) // TODO: To simulate loading. Yet to be handled +// val trades = myTradesRepository.fetch() +// _myTrades.value = trades?.trades ?: emptyList() +// } catch (e: Exception) { +// // Handle errors +// println("Error: ${e.message}") +// } +// } } override fun onViewAttached() { diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt index d6fb57b2..3230f615 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt @@ -21,9 +21,12 @@ import network.bisq.mobile.domain.data.model.MockOffer import network.bisq.mobile.presentation.ViewPresenter import network.bisq.mobile.presentation.ui.components.atoms.BisqButton import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.components.layout.BisqScrollLayout +import network.bisq.mobile.presentation.ui.components.molecules.MyOfferCard import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants import org.jetbrains.compose.resources.painterResource import org.koin.compose.koinInject @@ -31,6 +34,10 @@ interface IMyTrades : ViewPresenter { val myTrades: StateFlow> fun navigateToCurrencyList() + + fun createOffer() + + fun gotoTradeScreen(offer: MockOffer) } @Composable @@ -53,9 +60,17 @@ fun MyTradesScreen() { @Composable fun TradeList(presenter: IMyTrades, myTrades: List) { - LazyColumn(modifier = Modifier.padding(top = 48.dp)) { + LazyColumn( + verticalArrangement = Arrangement.spacedBy(BisqUIConstants.ScreenPadding), + horizontalAlignment = Alignment.CenterHorizontally, + ) { items(myTrades) { offer -> - //OfferCard( onClick = {} ) + MyOfferCard( + offerListItem = offer, + myTrade = true, + onClick = { presenter.gotoTradeScreen(offer) }, + onChatClick = {}, + ) } } @@ -65,22 +80,28 @@ fun TradeList(presenter: IMyTrades, myTrades: List) { fun NoTradesSection(presenter: IMyTrades) { BisqScrollLayout(verticalArrangement = Arrangement.Center) { Column( - modifier = Modifier.padding(vertical = 52.dp), + modifier = Modifier.padding(vertical = BisqUIConstants.ScreenPadding2X), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(64.dp) ) { Image( painterResource(Res.drawable.img_no_trades), "", - modifier = Modifier.height(272.dp).width(350.dp) + modifier = Modifier.height(220.dp).width(284.dp) ) + BisqGap.V2() BisqText.h3Regular( text = "A journey of a thousand miles begins with a first step!", color = BisqTheme.colors.light1, textAlign = TextAlign.Center ) + BisqGap.V4() BisqButton( text = "Start your first trade", - onClick = { presenter.navigateToCurrencyList() } + onClick = { presenter.navigateToCurrencyList() }, + ) + BisqGap.V1() + BisqButton( + text = "Create a offer", + onClick = { presenter.createOffer() } ) } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt index e2f329ec..6253b455 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt @@ -69,6 +69,22 @@ open class TradeFlowPresenter( setShowCloseTradeDialog(true) } + private val _showCancelTradeDialog = MutableStateFlow(false) + override val showCancelTradeDialog: StateFlow get() = _showCancelTradeDialog + override fun setShowCancelTradeDialog(value: Boolean) { + _showCancelTradeDialog.value = value + } + + override fun cancelTrade() { + setShowCancelTradeDialog(true) + } + + private val _showMediationDialog = MutableStateFlow(false) + override val showMediationDialog: StateFlow get() = _showMediationDialog + override fun setShowMediationDialog(value: Boolean) { + _showMediationDialog.value = value + } + override fun closeTradeConfirm() { setShowCloseTradeDialog(false) rootNavigator.popBackStack(Routes.Offerbook.name, inclusive = false, saveState = false) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt index 8de32dd4..17f7e18d 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt @@ -23,15 +23,14 @@ import network.bisq.mobile.presentation.ViewPresenter import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.components.layout.BisqStaticScaffold -import network.bisq.mobile.presentation.ui.components.molecules.BisqDialog import network.bisq.mobile.presentation.ui.components.molecules.TopBar -import network.bisq.mobile.presentation.ui.components.organisms.trades.CloseTradeCard import network.bisq.mobile.presentation.ui.components.organisms.trades.StepperSection import network.bisq.mobile.presentation.ui.components.organisms.trades.TradeFlowAccountDetails import network.bisq.mobile.presentation.ui.components.organisms.trades.TradeFlowBtcPayment import network.bisq.mobile.presentation.ui.components.organisms.trades.TradeFlowCompleted import network.bisq.mobile.presentation.ui.components.organisms.trades.TradeFlowFiatPayment import network.bisq.mobile.presentation.ui.components.organisms.trades.TradeHeader +import network.bisq.mobile.presentation.ui.components.organisms.trades.* import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.koin.compose.koinInject @@ -55,6 +54,13 @@ interface ITradeFlowPresenter : ViewPresenter { fun closeTradeConfirm() + val showCancelTradeDialog: StateFlow + fun setShowCancelTradeDialog(value: Boolean) + fun cancelTrade() + + val showMediationDialog: StateFlow + fun setShowMediationDialog(value: Boolean) + fun openWalletGuideLink() fun openTradeGuideLink() @@ -70,38 +76,57 @@ fun TradeFlowScreen() { val offer = presenter.offerListItems.collectAsState().value.first() val showCloseTradeDialog = presenter.showCloseTradeDialog.collectAsState().value + val showCancelTradeDialog = presenter.showCancelTradeDialog.collectAsState().value + val showMediationDialog = presenter.showMediationDialog.collectAsState().value + + val showDialog = showCloseTradeDialog || showCancelTradeDialog || showMediationDialog BisqStaticScaffold( - topBar = { TopBar("Trade - 07b9bab1") } + topBar = { TopBar("Trade - 07b9bab1", backConfirmation = true) } ) { - Box(modifier = Modifier.fillMaxSize().blur(if (showCloseTradeDialog) 12.dp else 0.dp)) { + Box( + modifier = Modifier + .fillMaxSize() + .blur(if (showDialog) 12.dp else 0.dp) + ) { Column( modifier = Modifier .verticalScroll(rememberScrollState()) .fillMaxSize() ) { - TradeHeader(offer) + TradeHeader( + offer, + onCancel = { presenter.setShowCancelTradeDialog(true) } + ) BisqGap.V2() TradeFlowStepper() } + if (showCloseTradeDialog) { - BisqDialog() { - CloseTradeCard( - onDismissRequest = { - presenter.setShowCloseTradeDialog(false) - }, - onConfirm = { - presenter.closeTradeConfirm() - } - ) + CloseTradeDialog( + onConfirm = { presenter.closeTradeConfirm() }, + onDismissRequest = { presenter.setShowCloseTradeDialog(false) }, + ) + } - } + if (showCancelTradeDialog) { + CancelTradeDialog( + onCancelConfirm= { presenter.setShowCancelTradeDialog(false) }, + onDismiss= { presenter.setShowCancelTradeDialog(false) } + ) + } + if (showMediationDialog) { + MediationRequestDialog( + onConfirm= { presenter.setShowMediationDialog(false) }, + onDismiss= { presenter.setShowMediationDialog(false) }, + ) } + } } } diff --git a/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt b/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt new file mode 100644 index 00000000..fbe3715b --- /dev/null +++ b/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt @@ -0,0 +1,8 @@ +package network.bisq.mobile.presentation.ui.components + +import androidx.compose.runtime.Composable + +@Composable +actual fun BackHandler(onBackPressed: () -> Unit) { + // TODO +} From 1dc567c0771e55cf57b83d3e53808cfbb2bc8e5b Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Fri, 20 Dec 2024 14:33:41 +0530 Subject: [PATCH 02/16] - Create offer FAB button in Offer list screen (#114) --- .../drawable/icon_add_filled_green.png | Bin 0 -> 858 bytes .../ui/components/atoms/icons/Icons.kt | 6 +++ .../ui/components/layout/ScrollScaffold.kt | 2 + .../ui/components/layout/StaticScaffold.kt | 2 + .../ui/uicases/offer/OffersListPresenter.kt | 18 ++++--- .../ui/uicases/offer/OffersListScreen.kt | 33 ++++++++++-- .../ui/uicases/offers/OffersListPresenter.kt | 47 ++++++++++++++++++ 7 files changed, 97 insertions(+), 11 deletions(-) create mode 100755 shared/presentation/src/commonMain/composeResources/drawable/icon_add_filled_green.png create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt diff --git a/shared/presentation/src/commonMain/composeResources/drawable/icon_add_filled_green.png b/shared/presentation/src/commonMain/composeResources/drawable/icon_add_filled_green.png new file mode 100755 index 0000000000000000000000000000000000000000..21ea4a5c982f5a719ce9e9035b53765629516cbc GIT binary patch literal 858 zcmV-g1Eu_lP)|CjDkc3IeDlR=gfrAgi||Gd1smoO`1AC@s* zOB=XwyjjTExhm(pg30HZ#qt<+QwYJW0k`-F-$snF{@5FLhuedpj!3D10hxDf=MCem zHi46+ph+;^aXt4f;At{SA0^-b6v{QASYF9eq%l@xgvqv5!KHzVy>gvT5?v04d;&ZfOs`*_0VDZ5#M{^P+mXpVWULFu6dEt0nFRN0m*LtZLGKhUKS6870ubek$Mye8E|BYEZp`->;v&ZYDu+;@Jyo_T9g3=f6CA kX@o58uG$J~6DSVw59ZOOJfmyif&c&j07*qoM6N<$f*1soCIA2c literal 0 HcmV?d00001 diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt index e908c6de..30b21bb1 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt @@ -29,6 +29,12 @@ import org.jetbrains.compose.resources.painterResource expect fun rememberPlatformImagePainter(platformImage: PlatformImage): Painter + +@Composable +fun AddIcon(modifier: Modifier = Modifier.size(16.dp)) { + Image(painterResource(Res.drawable.icon_add_filled_green), "Add icon", modifier = modifier) +} + @Composable fun ArrowDownIcon(modifier: Modifier = Modifier.size(12.dp)) { Image(painterResource(Res.drawable.icon_arrow_down), "Down arrow icon", modifier = modifier) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt index 01098b69..305aa1a1 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt @@ -20,6 +20,7 @@ fun BisqScrollScaffold( ), topBar: @Composable (() -> Unit)? = null, bottomBar: @Composable (() -> Unit)? = null, + fab: @Composable (() -> Unit)? = null, horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, verticalArrangement: Arrangement.Vertical = Arrangement.Top, content: @Composable ColumnScope.() -> Unit @@ -28,6 +29,7 @@ fun BisqScrollScaffold( containerColor = BisqTheme.colors.backgroundColor, topBar = topBar ?: {}, bottomBar = bottomBar ?: {}, + floatingActionButton = fab ?: {}, content = { BisqScrollLayout( padding = if (topBar != null) it else padding, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt index ac195ae3..628cbcf8 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt @@ -20,6 +20,7 @@ fun BisqStaticScaffold( ), topBar: @Composable (() -> Unit)? = null, bottomBar: @Composable (() -> Unit)? = null, + fab: @Composable (() -> Unit)? = null, horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, verticalArrangement: Arrangement.Vertical = Arrangement.Top, content: @Composable ColumnScope.() -> Unit @@ -28,6 +29,7 @@ fun BisqStaticScaffold( containerColor = BisqTheme.colors.backgroundColor, topBar = topBar ?: {}, bottomBar = bottomBar ?: {}, + floatingActionButton = fab ?: {}, content = { it -> BisqStaticLayout( padding = if (topBar != null) it else padding, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt index 5356793b..f1d747f9 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt @@ -15,15 +15,15 @@ class OffersListPresenter( mainPresenter: MainPresenter, offerbookServiceFacade: OfferbookServiceFacade, private val takeOfferPresenter: TakeOfferPresenter -) : BasePresenter(mainPresenter) { - val offerListItems: StateFlow> = +) : BasePresenter(mainPresenter), IOffersListPresenter { + override val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems private val _selectedDirection = MutableStateFlow(DirectionEnum.SELL) - val selectedDirection: StateFlow = _selectedDirection + override val selectedDirection: StateFlow = _selectedDirection - fun takeOffer(offerListItem: OfferListItemVO) { - takeOfferPresenter.selectOfferToTake(offerListItem) + override fun takeOffer(offer: OfferListItemVO) { + takeOfferPresenter.selectOfferToTake(offer) if (takeOfferPresenter.showAmountScreen()) { rootNavigator.navigate(Routes.TakeOfferTradeAmount.name) @@ -34,11 +34,15 @@ class OffersListPresenter( } } - fun chatForOffer(offerListItem: OfferListItemVO) { + override fun createOffer() { log.i { "chat for offer clicked " } } - fun onSelectDirection(direction: DirectionEnum) { + override fun chatForOffer(offer: OfferListItemVO) { + log.i { "chat for offer clicked " } + } + + override fun onSelectDirection(direction: DirectionEnum) { _selectedDirection.value = direction } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt index 93a1d684..a73d03c6 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt @@ -1,26 +1,44 @@ package network.bisq.mobile.presentation.ui.uicases.offer import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.material3.FloatingActionButton import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import cafe.adriel.lyricist.LocalStrings import network.bisq.mobile.domain.replicated.offer.DirectionEnum +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO +import network.bisq.mobile.presentation.ViewPresenter +import network.bisq.mobile.presentation.ui.components.atoms.icons.AddIcon import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.components.layout.BisqStaticScaffold import network.bisq.mobile.presentation.ui.components.molecules.DirectionToggle import network.bisq.mobile.presentation.ui.components.molecules.OfferCard import network.bisq.mobile.presentation.ui.components.molecules.TopBar import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle +import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.koin.compose.koinInject +interface IOffersListPresenter : ViewPresenter { + val offerListItems: StateFlow> + val selectedDirection: StateFlow + + fun takeOffer(offer: OfferListItemVO) + fun createOffer() + fun chatForOffer(offer: OfferListItemVO) + fun onSelectDirection(direction: DirectionEnum) +} + @Composable fun OffersListScreen() { val commonStrings = LocalStrings.current.common - val presenter: OffersListPresenter = koinInject() + val presenter: IOffersListPresenter = koinInject() RememberPresenterLifecycle(presenter) @@ -38,9 +56,16 @@ fun OffersListScreen() { RememberPresenterLifecycle(presenter) BisqStaticScaffold( - topBar = { - TopBar(title = commonStrings.common_offers) - }, + topBar = { TopBar(title = commonStrings.common_offers) }, + fab = { + FloatingActionButton( + onClick = { presenter.createOffer() }, + containerColor = BisqTheme.colors.primary, + contentColor = BisqTheme.colors.light1, + ) { + AddIcon(modifier = Modifier.size(24.dp)) + } + } ) { DirectionToggle( offerDirections, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt new file mode 100644 index 00000000..9a1811cc --- /dev/null +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt @@ -0,0 +1,47 @@ +package network.bisq.mobile.presentation.ui.uicases.offers + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.client.replicated_model.offer.Direction +import network.bisq.mobile.domain.data.model.OfferListItem +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade +import network.bisq.mobile.presentation.BasePresenter +import network.bisq.mobile.presentation.MainPresenter +import network.bisq.mobile.presentation.ViewPresenter +import network.bisq.mobile.presentation.ui.navigation.Routes + + +open class OffersListPresenter( + mainPresenter: MainPresenter, + private val offerbookServiceFacade: OfferbookServiceFacade, +) : BasePresenter(mainPresenter), IOffersListPresenter { + override val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems + + private val _selectedDirection = MutableStateFlow(Direction.SELL) + override val selectedDirection: StateFlow = _selectedDirection + + override fun onViewAttached() { + } + + override fun onViewUnattaching() { + } + + override fun takeOffer(offer: OfferListItem) { + log.i { "take offer clicked " } + //todo show take offer screen + rootNavigator.navigate(Routes.TakeOfferTradeAmount.name) + } + + override fun createOffer() { + log.i { "create offer clicked " } + rootNavigator.navigate(Routes.CreateOfferBuySell.name) + } + + override fun chatForOffer(offer: OfferListItem) { + log.i { "chat for offer clicked " } + } + + override fun onSelectDirection(direction: Direction) { + _selectedDirection.value = direction + } +} From 23429a0fb2fb2e7d7c0641004281c37013f36a40 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Fri, 20 Dec 2024 18:01:26 +0530 Subject: [PATCH 03/16] - showSnackBar() in BasePresenter. Tested in androidNode, androidClient. Having some other resource loading issue with iOS, not able to test. --- .../bisq/mobile/presentation/BasePresenter.kt | 20 +++++++++++++++- .../presentation/di/PresentationModule.kt | 11 +++++---- .../ui/components/layout/ScrollScaffold.kt | 12 +++++++++- .../ui/components/layout/StaticScaffold.kt | 12 +++++++++- .../ui/components/organisms/SnackBar.kt | 24 +++++++++++++++++++ .../ui/uicases/GettingStartedPresenter.kt | 3 --- .../ui/uicases/GettingStartedScreen.kt | 1 + .../ui/uicases/TabContainerPresenter.kt | 17 +++++++++++++ .../ui/uicases/TabContainerScreen.kt | 7 ++++-- .../ui/uicases/offers/OffersListPresenter.kt | 19 ++++++++------- .../startup/TrustedNodeSetupPresenter.kt | 3 +++ .../uicases/startup/TrustedNodeSetupScreen.kt | 4 +++- 12 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerPresenter.kt diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt index c7e0c908..e114d3c7 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt @@ -1,15 +1,19 @@ package network.bisq.mobile.presentation +import androidx.compose.material3.SnackbarHostState import androidx.annotation.CallSuper import androidx.navigation.NavHostController import kotlinx.coroutines.* import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import network.bisq.mobile.domain.data.BackgroundDispatcher import network.bisq.mobile.domain.data.model.BaseModel import network.bisq.mobile.i18n.AppStrings import network.bisq.mobile.domain.utils.Logging - /** * Presenter methods accesible by all views. Views should extend this interface when defining the behaviour expected for their presenter. */ @@ -29,6 +33,9 @@ interface ViewPresenter { */ fun getRootTabNavController(): NavHostController + fun getSnackState(): SnackbarHostState + fun showSnackbar(message: String, isError: Boolean = true) + /** * Navigate back in the stack */ @@ -71,6 +78,17 @@ abstract class BasePresenter(private val rootPresenter: MainPresenter?): ViewPre // Presenter is interactive by default private val _isInteractive = MutableStateFlow(true) override val isInteractive: StateFlow = _isInteractive + val snackbarHostState: SnackbarHostState = SnackbarHostState() + + override fun getSnackState(): SnackbarHostState { + return snackbarHostState + } + + override fun showSnackbar(message: String, isError: Boolean) { + uiScope.launch { + snackbarHostState.showSnackbar(message, withDismissAction = true) + } + } /** * @throws IllegalStateException if this presenter has no root diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt index 7dfcd9f9..c8495bf3 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt @@ -1,14 +1,12 @@ package network.bisq.mobile.presentation.di import network.bisq.mobile.client.ClientMainPresenter -import network.bisq.mobile.domain.UrlLauncher import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.AppPresenter import network.bisq.mobile.presentation.ui.components.molecules.ITopBarPresenter import network.bisq.mobile.presentation.ui.components.molecules.TopBarPresenter import network.bisq.mobile.presentation.ui.uicases.GettingStartedPresenter import network.bisq.mobile.presentation.ui.uicases.offer.MarketListPresenter -import network.bisq.mobile.presentation.ui.uicases.offer.OffersListPresenter import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferAmountPresenter import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferDirectionPresenter import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferMarketPresenter @@ -16,6 +14,10 @@ import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOffe import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferPresenter import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferPricePresenter import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferReviewPresenter +import network.bisq.mobile.presentation.ui.uicases.ITabContainerPresenter +import network.bisq.mobile.presentation.ui.uicases.TabContainerPresenter +import network.bisq.mobile.presentation.ui.uicases.offer.IOffersListPresenter +import network.bisq.mobile.presentation.ui.uicases.offers.OffersListPresenter import network.bisq.mobile.presentation.ui.uicases.settings.IPaymentAccountSettingsPresenter import network.bisq.mobile.presentation.ui.uicases.settings.ISettingsPresenter import network.bisq.mobile.presentation.ui.uicases.settings.IUserProfileSettingsPresenter @@ -54,9 +56,8 @@ val presentationModule = module { ) } -// single { TabContainerPresenter(get()) } bind ITabContainerPresenter::class - single { OnBoardingPresenter(get(), get(), get()) } bind IOnboardingPresenter::class + single { TabContainerPresenter(get()) } bind ITabContainerPresenter::class single { SettingsPresenter(get(), get()) } bind ISettingsPresenter::class @@ -81,7 +82,7 @@ val presentationModule = module { single { MarketListPresenter(get(), get()) } - single { OffersListPresenter(get(), get(), get()) } + single { OffersListPresenter(get(), get()) } bind IOffersListPresenter::class single { MyTradesPresenter( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt index 305aa1a1..d1190322 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/ScrollScaffold.kt @@ -2,10 +2,13 @@ package network.bisq.mobile.presentation.ui.components.layout import androidx.compose.foundation.layout.* import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import network.bisq.mobile.presentation.ui.components.organisms.BisqSnackbar import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants @@ -20,15 +23,22 @@ fun BisqScrollScaffold( ), topBar: @Composable (() -> Unit)? = null, bottomBar: @Composable (() -> Unit)? = null, + snackbarHostState: SnackbarHostState? = null, fab: @Composable (() -> Unit)? = null, horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, verticalArrangement: Arrangement.Vertical = Arrangement.Top, content: @Composable ColumnScope.() -> Unit ) { + Scaffold( containerColor = BisqTheme.colors.backgroundColor, topBar = topBar ?: {}, bottomBar = bottomBar ?: {}, + snackbarHost = { + if (snackbarHostState != null) { + BisqSnackbar(snackbarHostState = snackbarHostState) + } + }, floatingActionButton = fab ?: {}, content = { BisqScrollLayout( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt index 628cbcf8..0f5d1772 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/StaticScaffold.kt @@ -2,10 +2,13 @@ package network.bisq.mobile.presentation.ui.components.layout import androidx.compose.foundation.layout.* import androidx.compose.material3.Scaffold -import androidx.compose.material3.TopAppBar +import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import network.bisq.mobile.presentation.ui.components.organisms.BisqSnackbar import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants @@ -20,15 +23,22 @@ fun BisqStaticScaffold( ), topBar: @Composable (() -> Unit)? = null, bottomBar: @Composable (() -> Unit)? = null, + snackbarHostState: SnackbarHostState? = null, fab: @Composable (() -> Unit)? = null, horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, verticalArrangement: Arrangement.Vertical = Arrangement.Top, content: @Composable ColumnScope.() -> Unit ) { + Scaffold( containerColor = BisqTheme.colors.backgroundColor, topBar = topBar ?: {}, bottomBar = bottomBar ?: {}, + snackbarHost = { + if (snackbarHostState != null) { + BisqSnackbar(snackbarHostState = snackbarHostState) + } + }, floatingActionButton = fab ?: {}, content = { it -> BisqStaticLayout( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt new file mode 100644 index 00000000..c7ec12fa --- /dev/null +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt @@ -0,0 +1,24 @@ +package network.bisq.mobile.presentation.ui.components.organisms + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Snackbar +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants + +@Composable +fun BisqSnackbar(snackbarHostState: SnackbarHostState) { + SnackbarHost( + hostState = snackbarHostState, + snackbar = { data -> + Snackbar( + snackbarData = data, + containerColor = BisqTheme.colors.primary, + modifier = Modifier.padding(bottom = BisqUIConstants.ScreenPadding5X), + ) + } + ) +} \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedPresenter.kt index 5b49729c..8c603efe 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedPresenter.kt @@ -1,18 +1,15 @@ package network.bisq.mobile.presentation.ui.uicases -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import network.bisq.mobile.domain.data.repository.BisqStatsRepository import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes -import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferPresenter open class GettingStartedPresenter( mainPresenter: MainPresenter, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedScreen.kt index c2ff449e..8da98ab7 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/GettingStartedScreen.kt @@ -46,6 +46,7 @@ interface IGettingStarted : ViewPresenter { @Composable fun GettingStartedScreen() { val presenter: GettingStartedPresenter = koinInject() + val tabPresenter: ITabContainerPresenter = koinInject() val offersOnline: Number = presenter.offersOnline.collectAsState().value val publishedProfiles: Number = presenter.publishedProfiles.collectAsState().value diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerPresenter.kt new file mode 100644 index 00000000..957a096a --- /dev/null +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerPresenter.kt @@ -0,0 +1,17 @@ +package network.bisq.mobile.presentation.ui.uicases + +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import network.bisq.mobile.domain.data.repository.BisqStatsRepository +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.presentation.BasePresenter +import network.bisq.mobile.presentation.MainPresenter +import network.bisq.mobile.presentation.ui.navigation.Routes + +class TabContainerPresenter( + mainPresenter: MainPresenter, +) : BasePresenter(mainPresenter), ITabContainerPresenter { + +} \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt index c1f9f5b4..08307d45 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt @@ -5,6 +5,7 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import bisqapps.shared.presentation.generated.resources.* import bisqapps.shared.presentation.generated.resources.Res +import network.bisq.mobile.presentation.ViewPresenter import network.bisq.mobile.presentation.ui.AppPresenter import network.bisq.mobile.presentation.ui.components.layout.BisqStaticScaffold import network.bisq.mobile.presentation.ui.components.molecules.TopBar @@ -22,11 +23,12 @@ val navigationListItem = listOf( BottomNavigationItem("Settings", Routes.TabSettings.name, Res.drawable.icon_settings), ) +interface ITabContainerPresenter : ViewPresenter {} @Composable fun TabContainerScreen() { - val mainPresenter: AppPresenter = koinInject() - val navController: NavHostController = mainPresenter.getRootTabNavController() + val presenter: ITabContainerPresenter = koinInject() + val navController: NavHostController = presenter.getRootTabNavController() val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute by remember(navBackStackEntry) { derivedStateOf { @@ -69,6 +71,7 @@ fun TabContainerScreen() { } }) }, + snackbarHostState = presenter.getSnackState(), content = { TabNavGraph() } ) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt index 9a1811cc..83a28196 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt @@ -2,23 +2,24 @@ package network.bisq.mobile.presentation.ui.uicases.offers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import network.bisq.mobile.client.replicated_model.offer.Direction -import network.bisq.mobile.domain.data.model.OfferListItem +import network.bisq.mobile.domain.replicated.offer.DirectionEnum +import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ViewPresenter import network.bisq.mobile.presentation.ui.navigation.Routes +import network.bisq.mobile.presentation.ui.uicases.offer.IOffersListPresenter open class OffersListPresenter( mainPresenter: MainPresenter, private val offerbookServiceFacade: OfferbookServiceFacade, ) : BasePresenter(mainPresenter), IOffersListPresenter { - override val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems + override val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems - private val _selectedDirection = MutableStateFlow(Direction.SELL) - override val selectedDirection: StateFlow = _selectedDirection + private val _selectedDirection = MutableStateFlow(DirectionEnum.SELL) + override val selectedDirection: StateFlow = _selectedDirection override fun onViewAttached() { } @@ -26,7 +27,7 @@ open class OffersListPresenter( override fun onViewUnattaching() { } - override fun takeOffer(offer: OfferListItem) { + override fun takeOffer(offer: OfferListItemVO) { log.i { "take offer clicked " } //todo show take offer screen rootNavigator.navigate(Routes.TakeOfferTradeAmount.name) @@ -34,14 +35,14 @@ open class OffersListPresenter( override fun createOffer() { log.i { "create offer clicked " } - rootNavigator.navigate(Routes.CreateOfferBuySell.name) + rootNavigator.navigate(Routes.CreateOfferDirection.name) } - override fun chatForOffer(offer: OfferListItem) { + override fun chatForOffer(offer: OfferListItemVO) { log.i { "chat for offer clicked " } } - override fun onSelectDirection(direction: Direction) { + override fun onSelectDirection(direction: DirectionEnum) { _selectedDirection.value = direction } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt index d8df9323..76754b2e 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt @@ -59,6 +59,9 @@ class TrustedNodeSetupPresenter( } settingsRepository.update(updatedSettings) + + showSnackbar("Connected successfully") + // showSnackbar("Connected successfully and long text message with long list of english words") } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt index 1bdd7a68..0beed1e4 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt @@ -55,7 +55,9 @@ fun TrustedNodeSetupScreen(isWorkflow: Boolean = true) { RememberPresenterLifecycle(presenter) - BisqScrollScaffold { + BisqScrollScaffold( + snackbarHostState = presenter.getSnackState() + ) { BisqLogo() Spacer(modifier = Modifier.height(24.dp)) Column( From 40209c377ea802b9f9c94bf72d2ad4f28debb680 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Sat, 21 Dec 2024 15:31:01 +0530 Subject: [PATCH 04/16] - Copy, Paste, Scan QR (Tested in android) --- .../src/androidMain/AndroidManifest.xml | 5 + gradle/libs.versions.toml | 3 + iosClient/iosClient/Info.plist | 2 + shared/presentation/build.gradle.kts | 1 + .../drawable/icon_flash_light.png | Bin 0 -> 267 bytes .../drawable/icon_gallery.png | Bin 0 -> 282 bytes .../ui/components/atoms/CopyIconButton.kt | 19 + .../ui/components/atoms/TextField.kt | 10 + .../ui/components/atoms/icons/Icons.kt | 13 +- .../organisms/QRCodeScannerScreen.kt | 350 ++++++++++++++++++ .../presentation/ui/navigation/Routes.kt | 2 + .../ui/navigation/graph/RootNavGraph.kt | 5 + .../startup/TrustedNodeSetupPresenter.kt | 8 + .../uicases/startup/TrustedNodeSetupScreen.kt | 15 +- 14 files changed, 429 insertions(+), 4 deletions(-) create mode 100644 shared/presentation/src/commonMain/composeResources/drawable/icon_flash_light.png create mode 100644 shared/presentation/src/commonMain/composeResources/drawable/icon_gallery.png create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/CopyIconButton.kt create mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt diff --git a/androidClient/src/androidMain/AndroidManifest.xml b/androidClient/src/androidMain/AndroidManifest.xml index 1099348c..2649194f 100644 --- a/androidClient/src/androidMain/AndroidManifest.xml +++ b/androidClient/src/androidMain/AndroidManifest.xml @@ -1,10 +1,15 @@ + + + + + UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSCameraUsageDescription$(PRODUCT_NAME) camera description. + NSPhotoLibraryUsageDescription$(PRODUCT_NAME) photos description. diff --git a/shared/presentation/build.gradle.kts b/shared/presentation/build.gradle.kts index 5a876a4a..0aa57067 100644 --- a/shared/presentation/build.gradle.kts +++ b/shared/presentation/build.gradle.kts @@ -66,6 +66,7 @@ kotlin { implementation(libs.lyricist) implementation(libs.bignum) implementation(libs.coil.compose) + implementation(libs.qr.kit) } androidUnitTest.dependencies { implementation(libs.mock.io) diff --git a/shared/presentation/src/commonMain/composeResources/drawable/icon_flash_light.png b/shared/presentation/src/commonMain/composeResources/drawable/icon_flash_light.png new file mode 100644 index 0000000000000000000000000000000000000000..d9f2a4cffa9f162228990e7c92a5f8902e0b4f4a GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM3?#3wJbMaA*#!86xB}__VDRkOrx!0?JbU*3 z`Kz}tU%z|#5{TY_7_Z;G0E)bN3lx9x@-2`JM>`b`Bm?yemjw9*GcYoVh{=aW$HbJQ8ssTfSnV#f}GCu}`&o4eJ%@br$s*Mb^H0xc{ t5qi+$lzBqxg~f8y|8q>azpp84?$iv<-M0CsY=Jg0c)I$ztaD0e0syOfeI)<@ literal 0 HcmV?d00001 diff --git a/shared/presentation/src/commonMain/composeResources/drawable/icon_gallery.png b/shared/presentation/src/commonMain/composeResources/drawable/icon_gallery.png new file mode 100644 index 0000000000000000000000000000000000000000..bb5630af1794ed50b2515f12c0be8a2c178411d1 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM3?#3wJbMaAIR*HHxB}^C&z`+_@#6X0x6hxy zef8@7^H=Y{=mkWNB<7k;J9+BzpVhr%ovNt;HzTxTAcG%2@AZMmFUS3yS%hlIU)J#l3yGT{#|Wx zx@>&qw*HPiS>d(u7aurFPH%qv|M73TPuIMI6f9Zg)w9_2U-K$z Date: Thu, 26 Dec 2024 16:25:04 +0530 Subject: [PATCH 05/16] - Code refactor: CloseIcon --- .../ui/components/atoms/icons/Icons.kt | 14 ++ .../organisms/QRCodeScannerScreen.kt | 218 +----------------- 2 files changed, 22 insertions(+), 210 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt index 28f7496e..4b174671 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt @@ -2,8 +2,12 @@ package network.bisq.mobile.presentation.ui.components.atoms.icons import androidx.compose.foundation.Image import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.dp import bisqapps.shared.presentation.generated.resources.Res @@ -29,6 +33,16 @@ import org.jetbrains.compose.resources.painterResource expect fun rememberPlatformImagePainter(platformImage: PlatformImage): Painter +@Composable +fun CloseIcon(modifier: Modifier = Modifier.size(24.dp)) { + Icon( + Icons.Filled.Close, + "close", + modifier = modifier, + tint = Color.White + ) +} + @Composable fun AddIcon(modifier: Modifier = Modifier.size(16.dp)) { Image(painterResource(Res.drawable.icon_add_filled_green), "Add icon", modifier = modifier) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt index bb86116d..042894aa 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt @@ -42,10 +42,7 @@ import kotlinx.coroutines.launch import network.bisq.mobile.presentation.ui.components.atoms.BisqButton import network.bisq.mobile.presentation.ui.components.atoms.SvgImage import network.bisq.mobile.presentation.ui.components.atoms.SvgImageNames -import network.bisq.mobile.presentation.ui.components.atoms.icons.FlashLightIcon -import network.bisq.mobile.presentation.ui.components.atoms.icons.GalleryIcon -import network.bisq.mobile.presentation.ui.components.atoms.icons.StarFillIcon -import network.bisq.mobile.presentation.ui.components.atoms.icons.UserIcon +import network.bisq.mobile.presentation.ui.components.atoms.icons.* import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants @@ -55,6 +52,7 @@ import qrscanner.CameraLens import qrscanner.OverlayShape import qrscanner.QrScanner +// FinalTODO: De-couple from TrustedNodeSetup Presenter @Composable fun QRCodeScannerScreen() { val presenter: ITrustedNodeSetupPresenter = koinInject() @@ -117,9 +115,7 @@ fun QRCodeScannerScreen() { ) { BisqButton( text = "Upload from gallery", - onClick = { - openImagePicker = true - }, + onClick = { openImagePicker = true }, leftIcon = { GalleryIcon() } ) } @@ -131,14 +127,9 @@ fun QRCodeScannerScreen() { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { - Icon( - Icons.Filled.Close, - "close", - modifier = Modifier.size(24.dp).clickable { - presenter.goBack() - }, - tint = Color.White - ) + IconButton(onClick = { presenter.goBack() }) { + CloseIcon() + } IconButton( modifier = Modifier.clip(RoundedCornerShape(24.dp)).background( if (flashlightOn) { @@ -147,204 +138,11 @@ fun QRCodeScannerScreen() { Color.Transparent } ), - onClick = { - flashlightOn = !flashlightOn - } + onClick = { flashlightOn = !flashlightOn } ) { FlashLightIcon() } } } } -} - - -private fun DrawScope.drawQrBorderCanvas( - borderColor: Color = Color.White, - curve: Dp, - strokeWidth: Dp, - capSize: Dp, - cap: StrokeCap = StrokeCap.Square, - lineCap: StrokeCap = StrokeCap.Round, - width: Float = 0f, - height: Float = 0f, - top: Float = 0f, - left: Float = 0f -) { - - val curvePx = curve.toPx() - - val mCapSize = capSize.toPx() - - val sweepAngle = 90 / 2f - - val mCurve = curvePx * 2 - - val borderOutline = 5 - // bottom-right Arc - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 0f, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - width + left + borderOutline - mCurve, height + top + borderOutline - mCurve - ) - ) - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 90 - sweepAngle, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - width + left + borderOutline - mCurve, height + top + borderOutline - mCurve - ) - ) - - //bottom-left Arc - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 90f, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - left - borderOutline, height + top + borderOutline - mCurve - ) - ) - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 180 - sweepAngle, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - left - borderOutline, height + top + borderOutline - mCurve - ) - ) - - //Top-Left Arc - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 180f, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - left - borderOutline, top - borderOutline - ) - ) - - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 270 - sweepAngle, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - left - borderOutline, top - borderOutline - ) - ) - - // Top-right Arc - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 270f, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - width + left + borderOutline - mCurve, top - borderOutline - ) - ) - - drawArc( - color = borderColor, - style = Stroke(strokeWidth.toPx(), cap = cap), - startAngle = 360 - sweepAngle, - sweepAngle = sweepAngle, - useCenter = false, - size = Size(mCurve, mCurve), - topLeft = Offset( - width + left + borderOutline - mCurve, top - borderOutline - ) - ) - - //bottom-right Line - drawLine( - SolidColor(borderColor), - Offset(width + left + borderOutline, height + top - curvePx), - Offset(width + left + borderOutline, height + top - mCapSize), - strokeWidth.toPx(), - lineCap, - ) - - drawLine( - SolidColor(borderColor), - Offset(width + left - mCapSize, height + top + borderOutline), - Offset(width + left - curvePx, height + top + borderOutline), - strokeWidth.toPx(), - lineCap, - ) - - //bottom-left Line - drawLine( - SolidColor(borderColor), - Offset(left + mCapSize, height + top + borderOutline), - Offset(left + curvePx, height + top + borderOutline), - strokeWidth.toPx(), - lineCap, - ) - - drawLine( - SolidColor(borderColor), - Offset(left - borderOutline, height + top - curvePx), - Offset(left - borderOutline, height + top - mCapSize), - strokeWidth.toPx(), - lineCap - ) - - // Top-left line - drawLine( - SolidColor(borderColor), - Offset(left - borderOutline, curvePx + top), - Offset(left - borderOutline, mCapSize + top), - strokeWidth.toPx(), - lineCap, - ) - - drawLine( - SolidColor(borderColor), - Offset(curvePx + left, top - borderOutline), - Offset(left + mCapSize, top - borderOutline), - strokeWidth.toPx(), - lineCap, - ) - - // Top-right line - drawLine( - SolidColor(borderColor), - Offset(width + left - curvePx, top - borderOutline), - Offset(width + left - mCapSize, top - borderOutline), - strokeWidth.toPx(), - lineCap, - ) - - drawLine( - SolidColor(borderColor), - Offset(width + left + borderOutline, curvePx + top), - Offset(width + left + borderOutline, mCapSize + top), - strokeWidth.toPx(), - lineCap - ) - -} +} \ No newline at end of file From 9ad1e6595b332f6a3b29c179572bd6a2dbbb2e89 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Fri, 27 Dec 2024 10:24:59 +0530 Subject: [PATCH 06/16] Removed QR Code Scanner for this PR --- shared/presentation/build.gradle.kts | 1 - .../organisms/QRCodeScannerScreen.kt | 148 ------------------ .../presentation/ui/navigation/Routes.kt | 2 - .../ui/navigation/graph/RootNavGraph.kt | 5 - .../startup/TrustedNodeSetupPresenter.kt | 2 +- 5 files changed, 1 insertion(+), 157 deletions(-) delete mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt diff --git a/shared/presentation/build.gradle.kts b/shared/presentation/build.gradle.kts index 0aa57067..5a876a4a 100644 --- a/shared/presentation/build.gradle.kts +++ b/shared/presentation/build.gradle.kts @@ -66,7 +66,6 @@ kotlin { implementation(libs.lyricist) implementation(libs.bignum) implementation(libs.coil.compose) - implementation(libs.qr.kit) } androidUnitTest.dependencies { implementation(libs.mock.io) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt deleted file mode 100644 index 042894aa..00000000 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/QRCodeScannerScreen.kt +++ /dev/null @@ -1,148 +0,0 @@ -package network.bisq.mobile.presentation.ui.components.organisms - -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.graphics.drawscope.DrawScope -import androidx.compose.ui.graphics.drawscope.Stroke -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import network.bisq.mobile.presentation.ui.components.atoms.BisqButton -import network.bisq.mobile.presentation.ui.components.atoms.SvgImage -import network.bisq.mobile.presentation.ui.components.atoms.SvgImageNames -import network.bisq.mobile.presentation.ui.components.atoms.icons.* -import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle -import network.bisq.mobile.presentation.ui.theme.BisqTheme -import network.bisq.mobile.presentation.ui.theme.BisqUIConstants -import network.bisq.mobile.presentation.ui.uicases.startup.ITrustedNodeSetupPresenter -import org.koin.compose.koinInject -import qrscanner.CameraLens -import qrscanner.OverlayShape -import qrscanner.QrScanner - -// FinalTODO: De-couple from TrustedNodeSetup Presenter -@Composable -fun QRCodeScannerScreen() { - val presenter: ITrustedNodeSetupPresenter = koinInject() - var qrCodeURL by remember { mutableStateOf("") } - var flashlightOn by remember { mutableStateOf(false) } - var openImagePicker by remember { mutableStateOf(value = false) } - val coroutineScope = rememberCoroutineScope() - - RememberPresenterLifecycle(presenter) - - LaunchedEffect(Unit) { - delay(5000L) - flashlightOn = !flashlightOn - } - - LaunchedEffect(qrCodeURL) { - if (qrCodeURL.isNotEmpty()) { - presenter.updateBisqApiUrl(qrCodeURL) - presenter.goBackToSetupScreen() - } - } - - Box( - modifier = Modifier - .background(BisqTheme.colors.dark5) - .fillMaxSize() - .statusBarsPadding() - ) { - Box( - contentAlignment = Alignment.Center - ) { - QrScanner( - modifier = Modifier, - flashlightOn = flashlightOn, - cameraLens = CameraLens.Back, - openImagePicker = openImagePicker, - onCompletion = { - if (!openImagePicker){ - qrCodeURL = it - flashlightOn = false - } - }, - imagePickerHandler = { - openImagePicker = it - }, - onFailure = { - coroutineScope.launch { - if (it.isEmpty()) { - print("it is empty") - } else { - print("It throw $it") - } - } - }, - ) - } - - Column( - modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = BisqUIConstants.ScreenPadding2X) - ) { - BisqButton( - text = "Upload from gallery", - onClick = { openImagePicker = true }, - leftIcon = { GalleryIcon() } - ) - } - - Column { - Row( - modifier = Modifier.padding(horizontal = 14.dp, vertical = 20.dp) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween - ) { - IconButton(onClick = { presenter.goBack() }) { - CloseIcon() - } - IconButton( - modifier = Modifier.clip(RoundedCornerShape(24.dp)).background( - if (flashlightOn) { - BisqTheme.colors.light1 - } else { - Color.Transparent - } - ), - onClick = { flashlightOn = !flashlightOn } - ) { - FlashLightIcon() - } - } - } - } -} \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/Routes.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/Routes.kt index e302a50d..bb039fea 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/Routes.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/Routes.kt @@ -28,6 +28,4 @@ enum class Routes(val title: String) { CreateOfferPrice(title = "create_offer_trade_price"), CreateOfferPaymentMethod(title = "create_offer_payment_method"), CreateOfferReviewOffer(title = "create_offer_review_offer"), - - QRCodeScanner(title = "qr_code_scanner"), } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt index 6b12d283..51a22d11 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt @@ -12,7 +12,6 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import network.bisq.mobile.presentation.ui.navigation.Routes -import network.bisq.mobile.presentation.ui.components.organisms.QRCodeScannerScreen import network.bisq.mobile.presentation.ui.navigation.* import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.uicases.TabContainerScreen @@ -107,10 +106,6 @@ fun RootNavGraph(rootNavController: NavHostController) { composable(Routes.UserProfileSettings.name) { UserProfileSettingsScreen(showBackNavigation = true) } - - composable(Routes.QRCodeScanner.name) { - QRCodeScannerScreen() - } } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt index 5d2a32e8..114dad85 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt @@ -70,7 +70,7 @@ class TrustedNodeSetupPresenter( } override fun openQrScanner() { - rootNavigator.navigate(Routes.QRCodeScanner.name) + // rootNavigator.navigate(Routes.QRCodeScanner.name) } override fun goBackToSetupScreen() { From c2b7833bb1cf6375a39b76b750b9ebe50b209914 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Fri, 27 Dec 2024 10:47:18 +0530 Subject: [PATCH 07/16] Fix: Missing Icon imports --- .../bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt index 4b174671..e5a5b476 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/icons/Icons.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.unit.dp +import bisqapps.shared.presentation.generated.resources.* import bisqapps.shared.presentation.generated.resources.Res import bisqapps.shared.presentation.generated.resources.exchange_h_arrow import bisqapps.shared.presentation.generated.resources.exchange_v_arrow @@ -17,6 +18,7 @@ import bisqapps.shared.presentation.generated.resources.icon_arrow_down import bisqapps.shared.presentation.generated.resources.icon_bell import bisqapps.shared.presentation.generated.resources.icon_chat_outlined import bisqapps.shared.presentation.generated.resources.icon_copy +import bisqapps.shared.presentation.generated.resources.icon_gallery import bisqapps.shared.presentation.generated.resources.icon_info import bisqapps.shared.presentation.generated.resources.icon_language_grey import bisqapps.shared.presentation.generated.resources.icon_qr From b54a37dbfa44b7aca59885eb4a10585501819b4d Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Fri, 27 Dec 2024 11:36:16 +0530 Subject: [PATCH 08/16] Offer card layout - Experimenting --- .../ui/components/molecules/OfferCard.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt index a97e355a..931412bc 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt @@ -60,14 +60,15 @@ fun OfferCard( Column( horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.SpaceBetween, - modifier = Modifier.weight(2f) + modifier = Modifier.weight(3f) ) { // Len: 13 - "300 - 600 USD" // Len: 17 - "3,000 - 6,000 XYZ" // Len: 23 - "150,640 - 1,200,312 CRC" //if (offerListItem.formattedQuoteAmount.length < 18) { + // TODO: Currency is hardcoded now BisqText.baseRegular( - text = offerListItem.formattedQuoteAmount, + text = "${offerListItem.formattedPrice} ${offerListItem.bisqEasyOffer.market.quoteCurrencyCode}", color = BisqTheme.colors.primary ) /* } else { @@ -77,7 +78,8 @@ fun OfferCard( ) }*/ BisqGap.H1() - Row { + Row(verticalAlignment = Alignment.CenterVertically) { + /* BisqText.smallRegular( text = "@ ", color = BisqTheme.colors.grey2 @@ -86,8 +88,7 @@ fun OfferCard( text = offerListItem.formattedPriceSpec, color = BisqTheme.colors.light1 ) - } - Row(verticalAlignment = Alignment.CenterVertically) { + */ LanguageIcon() BisqText.smallRegular( text = " : ", @@ -97,6 +98,14 @@ fun OfferCard( text = offerListItem.bisqEasyOffer.supportedLanguageCodes.joinToString(", ").uppercase(), color = BisqTheme.colors.light1 ) + BisqGap.H1() + BisqText.smallRegular( + text = offerListItem.formattedPriceSpec, + color = BisqTheme.colors.light1 + ) + } + Row(verticalAlignment = Alignment.CenterVertically) { + // Row(verticalAlignment = Alignment.CenterVertically) { // LanguageIcon() // BisqText.largeRegular( From 38c354458bf31044ea471217564ad2643daac195 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Tue, 31 Dec 2024 12:49:21 +0530 Subject: [PATCH 09/16] - file refactorings: Removed duplicate OfferListPresenter in 'offers'; moved all files from 'offers' to 'offer' and from 'trades' to 'trade' --- .../presentation/di/PresentationModule.kt | 12 ++--- .../trades/TradeFlowAccountDetails.kt | 2 +- .../organisms/trades/TradeFlowFiatPayment.kt | 2 +- .../ui/navigation/graph/RootNavGraph.kt | 2 +- .../ui/navigation/graph/TabNavGraph.kt | 2 +- .../ui/uicases/offer/OffersListScreen.kt | 5 +- .../ui/uicases/offers/OffersListPresenter.kt | 48 ------------------- .../{trades => trade}/MyTradesPresenter.kt | 2 +- .../{trades => trade}/MyTradesScreen.kt | 2 +- .../{trades => trade}/TradeFlowPresenter.kt | 2 +- .../{trades => trade}/TradeFlowScreen.kt | 2 +- 11 files changed, 17 insertions(+), 64 deletions(-) delete mode 100644 shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt rename shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/{trades => trade}/MyTradesPresenter.kt (97%) rename shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/{trades => trade}/MyTradesScreen.kt (98%) rename shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/{trades => trade}/TradeFlowPresenter.kt (98%) rename shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/{trades => trade}/TradeFlowScreen.kt (99%) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt index c8495bf3..8dea9469 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt @@ -17,7 +17,7 @@ import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOffe import network.bisq.mobile.presentation.ui.uicases.ITabContainerPresenter import network.bisq.mobile.presentation.ui.uicases.TabContainerPresenter import network.bisq.mobile.presentation.ui.uicases.offer.IOffersListPresenter -import network.bisq.mobile.presentation.ui.uicases.offers.OffersListPresenter +import network.bisq.mobile.presentation.ui.uicases.offer.OffersListPresenter import network.bisq.mobile.presentation.ui.uicases.settings.IPaymentAccountSettingsPresenter import network.bisq.mobile.presentation.ui.uicases.settings.ISettingsPresenter import network.bisq.mobile.presentation.ui.uicases.settings.IUserProfileSettingsPresenter @@ -34,10 +34,10 @@ import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferAmo import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferPaymentMethodPresenter import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferPresenter import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferReviewPresenter -import network.bisq.mobile.presentation.ui.uicases.trades.IMyTrades -import network.bisq.mobile.presentation.ui.uicases.trades.ITradeFlowPresenter -import network.bisq.mobile.presentation.ui.uicases.trades.MyTradesPresenter -import network.bisq.mobile.presentation.ui.uicases.trades.TradeFlowPresenter +import network.bisq.mobile.presentation.ui.uicases.trade.IMyTrades +import network.bisq.mobile.presentation.ui.uicases.trade.ITradeFlowPresenter +import network.bisq.mobile.presentation.ui.uicases.trade.MyTradesPresenter +import network.bisq.mobile.presentation.ui.uicases.trade.TradeFlowPresenter import org.koin.dsl.bind import org.koin.dsl.module @@ -82,7 +82,7 @@ val presentationModule = module { single { MarketListPresenter(get(), get()) } - single { OffersListPresenter(get(), get()) } bind IOffersListPresenter::class + single { OffersListPresenter(get(), get(), get()) } bind IOffersListPresenter::class single { MyTradesPresenter( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowAccountDetails.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowAccountDetails.kt index 850fac32..8b1a1d59 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowAccountDetails.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowAccountDetails.kt @@ -9,7 +9,7 @@ import cafe.adriel.lyricist.LocalStrings import network.bisq.mobile.presentation.ui.components.atoms.* import network.bisq.mobile.presentation.ui.components.atoms.layout.* import network.bisq.mobile.presentation.ui.theme.BisqUIConstants -import network.bisq.mobile.presentation.ui.uicases.trades.ITradeFlowPresenter +import network.bisq.mobile.presentation.ui.uicases.trade.ITradeFlowPresenter import org.koin.compose.koinInject /** diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowFiatPayment.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowFiatPayment.kt index 4db81545..eaa18661 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowFiatPayment.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/trades/TradeFlowFiatPayment.kt @@ -16,7 +16,7 @@ import network.bisq.mobile.presentation.ui.components.atoms.* import network.bisq.mobile.presentation.ui.components.atoms.layout.* import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants -import network.bisq.mobile.presentation.ui.uicases.trades.ITradeFlowPresenter +import network.bisq.mobile.presentation.ui.uicases.trade.ITradeFlowPresenter import org.koin.compose.koinInject /** diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt index 51a22d11..97684386 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/RootNavGraph.kt @@ -30,7 +30,7 @@ import network.bisq.mobile.presentation.ui.uicases.startup.TrustedNodeSetupScree import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferPaymentMethodScreen import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferReviewTradeScreen import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferTradeAmountScreen -import network.bisq.mobile.presentation.ui.uicases.trades.TradeFlowScreen +import network.bisq.mobile.presentation.ui.uicases.trade.TradeFlowScreen @Composable fun RootNavGraph(rootNavController: NavHostController) { diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/TabNavGraph.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/TabNavGraph.kt index 8a493795..a344e833 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/TabNavGraph.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/navigation/graph/TabNavGraph.kt @@ -15,7 +15,7 @@ import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.uicases.GettingStartedScreen import network.bisq.mobile.presentation.ui.uicases.offer.MarketListScreen import network.bisq.mobile.presentation.ui.uicases.settings.SettingsScreen -import network.bisq.mobile.presentation.ui.uicases.trades.MyTradesScreen +import network.bisq.mobile.presentation.ui.uicases.trade.MyTradesScreen import org.koin.compose.koinInject @Composable diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt index a73d03c6..ba56388d 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt @@ -15,6 +15,7 @@ import network.bisq.mobile.domain.replicated.offer.DirectionEnum import kotlinx.coroutines.flow.StateFlow import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO import network.bisq.mobile.presentation.ViewPresenter +import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.icons.AddIcon import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.components.layout.BisqStaticScaffold @@ -50,8 +51,8 @@ fun OffersListScreen() { val offerListItems = presenter.offerListItems.collectAsState().value val selectedDirection = presenter.selectedDirection.collectAsState().value - val filteredList = offerListItems.filter { it.bisqEasyOffer.direction == selectedDirection } - val sortedList = filteredList.sortedByDescending { it.bisqEasyOffer.date } + // val filteredList = offerListItems.filter { it.bisqEasyOffer.direction == selectedDirection } + val sortedList = offerListItems.sortedByDescending { it.bisqEasyOffer.date } RememberPresenterLifecycle(presenter) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt deleted file mode 100644 index 83a28196..00000000 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt +++ /dev/null @@ -1,48 +0,0 @@ -package network.bisq.mobile.presentation.ui.uicases.offers - -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import network.bisq.mobile.domain.replicated.offer.DirectionEnum -import network.bisq.mobile.domain.replicated.offer.bisq_easy.OfferListItemVO -import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade -import network.bisq.mobile.presentation.BasePresenter -import network.bisq.mobile.presentation.MainPresenter -import network.bisq.mobile.presentation.ViewPresenter -import network.bisq.mobile.presentation.ui.navigation.Routes -import network.bisq.mobile.presentation.ui.uicases.offer.IOffersListPresenter - - -open class OffersListPresenter( - mainPresenter: MainPresenter, - private val offerbookServiceFacade: OfferbookServiceFacade, -) : BasePresenter(mainPresenter), IOffersListPresenter { - override val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems - - private val _selectedDirection = MutableStateFlow(DirectionEnum.SELL) - override val selectedDirection: StateFlow = _selectedDirection - - override fun onViewAttached() { - } - - override fun onViewUnattaching() { - } - - override fun takeOffer(offer: OfferListItemVO) { - log.i { "take offer clicked " } - //todo show take offer screen - rootNavigator.navigate(Routes.TakeOfferTradeAmount.name) - } - - override fun createOffer() { - log.i { "create offer clicked " } - rootNavigator.navigate(Routes.CreateOfferDirection.name) - } - - override fun chatForOffer(offer: OfferListItemVO) { - log.i { "chat for offer clicked " } - } - - override fun onSelectDirection(direction: DirectionEnum) { - _selectedDirection.value = direction - } -} diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt similarity index 97% rename from shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt rename to shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt index 217b3f95..dcc9875d 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt @@ -1,4 +1,4 @@ -package network.bisq.mobile.presentation.ui.uicases.trades +package network.bisq.mobile.presentation.ui.uicases.trade import androidx.compose.runtime.mutableStateOf import kotlinx.coroutines.CoroutineScope diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesScreen.kt similarity index 98% rename from shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt rename to shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesScreen.kt index 3230f615..b443e9ce 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesScreen.kt @@ -1,4 +1,4 @@ -package network.bisq.mobile.presentation.ui.uicases.trades +package network.bisq.mobile.presentation.ui.uicases.trade import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/TradeFlowPresenter.kt similarity index 98% rename from shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt rename to shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/TradeFlowPresenter.kt index 6253b455..e73e6faa 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/TradeFlowPresenter.kt @@ -1,4 +1,4 @@ -package network.bisq.mobile.presentation.ui.uicases.trades +package network.bisq.mobile.presentation.ui.uicases.trade import androidx.compose.runtime.Composable import cafe.adriel.lyricist.LocalStrings diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/TradeFlowScreen.kt similarity index 99% rename from shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt rename to shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/TradeFlowScreen.kt index 17f7e18d..7f5fb3c5 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/TradeFlowScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/TradeFlowScreen.kt @@ -1,4 +1,4 @@ -package network.bisq.mobile.presentation.ui.uicases.trades +package network.bisq.mobile.presentation.ui.uicases.trade import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Box From e6c3c251a48a93e77919d939e8b9478b3702f6d4 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Tue, 31 Dec 2024 13:22:41 +0530 Subject: [PATCH 10/16] - [fix] Create Offer nav issue --- .../bisq/mobile/presentation/di/PresentationModule.kt | 5 +++-- .../presentation/ui/uicases/offer/OffersListPresenter.kt | 7 +++++-- .../presentation/ui/uicases/trade/MyTradesPresenter.kt | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt index 8dea9469..2e40a471 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt @@ -82,12 +82,13 @@ val presentationModule = module { single { MarketListPresenter(get(), get()) } - single { OffersListPresenter(get(), get(), get()) } bind IOffersListPresenter::class + single { OffersListPresenter(get(), get(), get(), get()) } bind IOffersListPresenter::class single { MyTradesPresenter( get(), - get() + get(), + get(), ) } bind IMyTrades::class diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt index f1d747f9..d082aba0 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListPresenter.kt @@ -8,13 +8,15 @@ import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes +import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferPresenter import network.bisq.mobile.presentation.ui.uicases.trade.take_offer.TakeOfferPresenter class OffersListPresenter( mainPresenter: MainPresenter, offerbookServiceFacade: OfferbookServiceFacade, - private val takeOfferPresenter: TakeOfferPresenter + private val takeOfferPresenter: TakeOfferPresenter, + private val createOfferPresenter: CreateOfferPresenter ) : BasePresenter(mainPresenter), IOffersListPresenter { override val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems @@ -35,7 +37,8 @@ class OffersListPresenter( } override fun createOffer() { - log.i { "chat for offer clicked " } + createOfferPresenter.onStartCreateOffer() + rootNavigator.navigate(Routes.CreateOfferDirection.name) } override fun chatForOffer(offer: OfferListItemVO) { diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt index dcc9875d..f04b2272 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt @@ -14,11 +14,12 @@ import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes +import network.bisq.mobile.presentation.ui.uicases.offer.create_offer.CreateOfferPresenter class MyTradesPresenter( mainPresenter: MainPresenter, private val offerbookServiceFacade: OfferbookServiceFacade, - // private val myTradesRepository: MyTradesRepository, + private val createOfferPresenter: CreateOfferPresenter ) : BasePresenter(mainPresenter), IMyTrades { private val _myTrades = MutableStateFlow>(emptyList()) @@ -40,6 +41,7 @@ class MyTradesPresenter( override fun createOffer() { log.i { "Goto create offer" } + createOfferPresenter.onStartCreateOffer() rootNavigator.navigate(Routes.CreateOfferDirection.name) } From b670152e6845fdcc8c0856aca4759bc9974f632e Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Tue, 31 Dec 2024 14:21:45 +0530 Subject: [PATCH 11/16] - Remove Take offer nav stack, when Take offer flow is confirmed and TradeFlow nav happens; Snackbar warnings in PaymentMethod screen, when payment method is not selected --- .../ui/components/layout/MultiScreenWizardScaffold.kt | 10 ++++++++-- .../presentation/ui/uicases/offer/OffersListScreen.kt | 4 ++-- .../take_offer/TakeOfferPaymentMethodPresenter.kt | 7 +++++++ .../trade/take_offer/TakeOfferPaymentMethodScreen.kt | 3 ++- .../trade/take_offer/TakeOfferReviewPresenter.kt | 4 +++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/MultiScreenWizardScaffold.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/MultiScreenWizardScaffold.kt index ba4caa7c..90065a1d 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/MultiScreenWizardScaffold.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/layout/MultiScreenWizardScaffold.kt @@ -2,6 +2,7 @@ package network.bisq.mobile.presentation.ui.components.layout import androidx.compose.foundation.layout.* import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -24,6 +25,7 @@ fun MultiScreenWizardScaffold( nextOnClick: (() -> Unit)? = null, horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally, useStaticScaffold: Boolean = false, + snackbarHostState: SnackbarHostState? = null, content: @Composable ColumnScope.() -> Unit ) { @@ -33,24 +35,27 @@ fun MultiScreenWizardScaffold( bottomBar: @Composable (() -> Unit)?, hAlignment: Alignment.Horizontal, vArrangement: Arrangement.Vertical, + snackbarHostState: SnackbarHostState?, content: @Composable ColumnScope.() -> Unit ) -> Unit = - if (useStaticScaffold) { padding, topBar, bottomBar, hAlignment, verticalArrangement, innerContent -> + if (useStaticScaffold) { padding, topBar, bottomBar, hAlignment, verticalArrangement, snackState, innerContent -> BisqStaticScaffold( padding = padding, topBar = topBar, bottomBar = bottomBar, horizontalAlignment = hAlignment, verticalArrangement = verticalArrangement, + snackbarHostState = snackState, content = innerContent ) - } else { padding, topBar, bottomBar, hAlignment, verticalArrangement, innerContent -> + } else { padding, topBar, bottomBar, hAlignment, verticalArrangement, snackState, innerContent -> BisqScrollScaffold( padding = padding, topBar = topBar, bottomBar = bottomBar, horizontalAlignment = hAlignment, verticalArrangement = verticalArrangement, + snackbarHostState = snackState, content = innerContent ) } @@ -98,6 +103,7 @@ fun MultiScreenWizardScaffold( }, horizontalAlignment, Arrangement.Top, + snackbarHostState, ) { BisqProgressBar( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt index ba56388d..0f96656d 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/OffersListScreen.kt @@ -51,8 +51,8 @@ fun OffersListScreen() { val offerListItems = presenter.offerListItems.collectAsState().value val selectedDirection = presenter.selectedDirection.collectAsState().value - // val filteredList = offerListItems.filter { it.bisqEasyOffer.direction == selectedDirection } - val sortedList = offerListItems.sortedByDescending { it.bisqEasyOffer.date } + val filteredList = offerListItems.filter { it.bisqEasyOffer.direction == selectedDirection } + val sortedList = filteredList.sortedByDescending { it.bisqEasyOffer.date } RememberPresenterLifecycle(presenter) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt index 6c618f7b..d3f69cc8 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt @@ -52,6 +52,13 @@ class TakeOfferPaymentMethodPresenter( commitToModel() rootNavigator.navigate(Routes.TakeOfferReviewTrade.name) } else { + var warningMessage = "Please select both Fiat and Bitcoin payment methods" + if (quoteSidePaymentMethod == null && baseSidePaymentMethod != null) { + warningMessage = "Please select fiat payment method" + } else if (quoteSidePaymentMethod != null && baseSidePaymentMethod == null) { + warningMessage = "Please select settlement method" + } + showSnackbar(warningMessage) //TODO show user feedback if one or both are not selected. // Note the data is set at the service layer, so if there is only one payment method we // have it set at the service. We do not need to check here if we have the multiple options. diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt index eb6c68bd..13026200 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt @@ -50,7 +50,8 @@ fun TakeOfferPaymentMethodScreen() { stepIndex = 2, stepsLength = 3, prevOnClick = { presenter.onBack() }, - nextOnClick = { presenter.onNext() } + nextOnClick = { presenter.onNext() }, + snackbarHostState = presenter.getSnackState(), ) { BisqText.h3Regular( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt index 110cd37f..380c7dc4 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt @@ -111,7 +111,9 @@ class TakeOfferReviewPresenter( } fun onGoToOpenTrades() { - rootNavigator.navigate(Routes.TradeFlow.name) + rootNavigator.navigate(Routes.TradeFlow.name) { + popUpTo(Routes.TakeOfferTradeAmount.name) { inclusive = true } + } } From dcff1f5520d4ae638f063ae68d52b12bb9a006a5 Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Tue, 31 Dec 2024 15:06:49 +0530 Subject: [PATCH 12/16] - removed qr related code; removed dead code; Snackbar color - Dark text over white BG --- .../src/androidMain/AndroidManifest.xml | 5 ---- gradle/libs.versions.toml | 3 -- iosClient/iosClient/Info.plist | 2 -- .../ui/components/molecules/MyOfferCard.kt | 30 +------------------ .../ui/components/molecules/OfferCard.kt | 30 +------------------ .../ui/components/organisms/SnackBar.kt | 7 +++-- .../startup/TrustedNodeSetupPresenter.kt | 4 --- .../uicases/startup/TrustedNodeSetupScreen.kt | 5 +--- .../ui/uicases/trade/MyTradesPresenter.kt | 10 ------- 9 files changed, 8 insertions(+), 88 deletions(-) diff --git a/androidClient/src/androidMain/AndroidManifest.xml b/androidClient/src/androidMain/AndroidManifest.xml index 2649194f..1099348c 100644 --- a/androidClient/src/androidMain/AndroidManifest.xml +++ b/androidClient/src/androidMain/AndroidManifest.xml @@ -1,15 +1,10 @@ - - - - - UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - NSCameraUsageDescription$(PRODUCT_NAME) camera description. - NSPhotoLibraryUsageDescription$(PRODUCT_NAME) photos description. diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt index 16fa8eed..aff8e99c 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/MyOfferCard.kt @@ -76,12 +76,6 @@ fun MyOfferCard( text = "mockOffer.formattedQuoteAmount", color = BisqTheme.colors.primary ) - /* } else { - BisqText.smallRegular( - text = offerListItem.formattedQuoteAmount, - color = BisqTheme.colors.primary - ) - }*/ BisqGap.H1() Row { BisqText.smallRegular( @@ -103,33 +97,11 @@ fun MyOfferCard( text = "mockOffer.bisqEasyOffer.supportedLanguageCodes.joinToString().uppercase()", color = BisqTheme.colors.light1 ) -// Row(verticalAlignment = Alignment.CenterVertically) { -// LanguageIcon() -// BisqText.largeRegular( -// text = ": ${offerListItem. }", -// color = BisqTheme.colors.grey1 -// ) -// } BisqGap.H1() - // Len: 13 - "300 - 600 USD" - // Len: 17 - "3,000 - 6,000 XYZ" - // Len: 23 - "150,640 - 1,200,312 CRC" - /* - if (offerListItem.formattedQuoteAmount.length < 18) { - BisqText.baseRegular( - text = offerListItem.formattedQuoteAmount, - color = BisqTheme.colors.light1 - ) - } else { - BisqText.smallRegular( - text = offerListItem.formattedQuoteAmount, - color = BisqTheme.colors.light1 - ) - } - */ } } /* + // TODO: Keeping this code for later. If we want to have Chat button here again if (!myTrade) { BisqVDivider() Column( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt index 931412bc..3c14ce76 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt @@ -62,33 +62,12 @@ fun OfferCard( verticalArrangement = Arrangement.SpaceBetween, modifier = Modifier.weight(3f) ) { - // Len: 13 - "300 - 600 USD" - // Len: 17 - "3,000 - 6,000 XYZ" - // Len: 23 - "150,640 - 1,200,312 CRC" - //if (offerListItem.formattedQuoteAmount.length < 18) { - // TODO: Currency is hardcoded now BisqText.baseRegular( text = "${offerListItem.formattedPrice} ${offerListItem.bisqEasyOffer.market.quoteCurrencyCode}", color = BisqTheme.colors.primary ) - /* } else { - BisqText.smallRegular( - text = offerListItem.formattedQuoteAmount, - color = BisqTheme.colors.primary - ) - }*/ BisqGap.H1() Row(verticalAlignment = Alignment.CenterVertically) { - /* - BisqText.smallRegular( - text = "@ ", - color = BisqTheme.colors.grey2 - ) - BisqText.smallRegular( - text = offerListItem.formattedPriceSpec, - color = BisqTheme.colors.light1 - ) - */ LanguageIcon() BisqText.smallRegular( text = " : ", @@ -105,14 +84,6 @@ fun OfferCard( ) } Row(verticalAlignment = Alignment.CenterVertically) { - -// Row(verticalAlignment = Alignment.CenterVertically) { -// LanguageIcon() -// BisqText.largeRegular( -// text = ": ${offerListItem. }", -// color = BisqTheme.colors.grey1 -// ) -// } BisqGap.H1() // Len: 13 - "300 - 600 USD" // Len: 17 - "3,000 - 6,000 XYZ" @@ -131,6 +102,7 @@ fun OfferCard( } } /* + // TODO: This code is kept here, so ChatButton can be added back in future, when required if (!myTrade) { BisqVDivider() Column( diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt index c7ec12fa..51bff8f8 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/organisms/SnackBar.kt @@ -16,8 +16,11 @@ fun BisqSnackbar(snackbarHostState: SnackbarHostState) { snackbar = { data -> Snackbar( snackbarData = data, - containerColor = BisqTheme.colors.primary, - modifier = Modifier.padding(bottom = BisqUIConstants.ScreenPadding5X), + // containerColor = BisqTheme.colors.primary, + containerColor = BisqTheme.colors.light1.copy(alpha = 0.95f), + contentColor = BisqTheme.colors.grey5, + dismissActionContentColor = BisqTheme.colors.grey5, + modifier = Modifier.padding(bottom = BisqUIConstants.ScreenPadding2X), ) } ) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt index 114dad85..867bd230 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupPresenter.kt @@ -68,10 +68,6 @@ class TrustedNodeSetupPresenter( override fun navigateToNextScreen() { rootNavigator.navigate(Routes.CreateProfile.name) } - - override fun openQrScanner() { - // rootNavigator.navigate(Routes.QRCodeScanner.name) - } override fun goBackToSetupScreen() { rootNavigator.popBackStack() diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt index 19db35a7..b270e8ae 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/TrustedNodeSetupScreen.kt @@ -43,7 +43,6 @@ interface ITrustedNodeSetupPresenter: ViewPresenter { fun navigateToNextScreen() - fun openQrScanner() fun goBackToSetupScreen() } @@ -101,9 +100,7 @@ fun TrustedNodeSetupScreen(isWorkflow: Boolean = true) { BisqButton( text = "Scan", - onClick = { - presenter.openQrScanner() - }, + onClick = {}, leftIcon= { ScanIcon() } ) } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt index f04b2272..ade80755 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/MyTradesPresenter.kt @@ -51,16 +51,6 @@ class MyTradesPresenter( } private fun refresh() { -// CoroutineScope(BackgroundDispatcher).launch { -// try { -// delay(1000) // TODO: To simulate loading. Yet to be handled -// val trades = myTradesRepository.fetch() -// _myTrades.value = trades?.trades ?: emptyList() -// } catch (e: Exception) { -// // Handle errors -// println("Error: ${e.message}") -// } -// } } override fun onViewAttached() { From 4cbab23d1feabff234e697cac098381a8a07fd9e Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Wed, 1 Jan 2025 19:01:31 +0530 Subject: [PATCH 13/16] Take offer UI Improvements - AmountScreen - Amount selector - Placed vertically center; - PaymentMethodScreen - Make use of PaymentMethodCard as done in Createoffer flow; - ReviewScreen - BisqUIConstants; Misc UI Improvements - CreateOfferPaymentMethodScreen - Adjust spacing; - BisqAmount select - Comment on usage --- .../ui/components/molecules/AmountSelector.kt | 8 +- .../CreateOfferPaymentMethodScreen.kt | 2 +- .../trade/take_offer/TakeOfferAmountScreen.kt | 33 +++-- .../TakeOfferPaymentMethodPresenter.kt | 29 ++++ .../TakeOfferPaymentMethodScreen.kt | 132 ++++-------------- .../trade/take_offer/TakeOfferReviewScreen.kt | 2 +- 6 files changed, 87 insertions(+), 119 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/AmountSelector.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/AmountSelector.kt index dcf2d558..a90c71ef 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/AmountSelector.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/AmountSelector.kt @@ -15,7 +15,13 @@ import network.bisq.mobile.presentation.ui.components.atoms.BisqSlider import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.BtcSatsText import network.bisq.mobile.presentation.ui.theme.BisqTheme +import network.bisq.mobile.presentation.ui.theme.BisqUIConstants +// ToDiscuss: +// buddha: Ideally this component should deal only with Fiat values (as Double) and have one valueChange() event +// so `initialSliderPosition` will become `defaultValue`, +// which will be some value between `formattedMinAmount` and `formattedMaxAmount` +// onSliderValueChange() / onTextValueChange() will become onValueChange(value: Double) -> Unit @Composable fun BisqAmountSelector( fiatCurrencyCode: String, @@ -48,7 +54,7 @@ fun BisqAmountSelector( Column( modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(16.dp), + verticalArrangement = Arrangement.spacedBy(BisqUIConstants.ScreenPadding), horizontalAlignment = Alignment.CenterHorizontally ) { diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferPaymentMethodScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferPaymentMethodScreen.kt index 96feece2..4f4e4d9a 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferPaymentMethodScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferPaymentMethodScreen.kt @@ -37,7 +37,7 @@ fun CreateOfferPaymentMethodSelectorScreen() { color = BisqTheme.colors.light1 ) - BisqGap.V1() + BisqGap.V2() PaymentMethodCard( title = presenter.quoteSideHeadline, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferAmountScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferAmountScreen.kt index acb7e259..700c5282 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferAmountScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferAmountScreen.kt @@ -1,7 +1,6 @@ package network.bisq.mobile.presentation.ui.uicases.trade.take_offer -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @@ -25,7 +24,8 @@ fun TakeOfferTradeAmountScreen() { stepIndex = 1, stepsLength = 3, prevOnClick = { presenter.onBack() }, - nextOnClick = { presenter.onNext() } + nextOnClick = { presenter.onNext() }, + useStaticScaffold = true ) { BisqText.h3Regular( text = strings.bisqEasy_takeOffer_amount_headline_buyer, @@ -41,17 +41,20 @@ fun TakeOfferTradeAmountScreen() { color = BisqTheme.colors.grey2 ) - Spacer(modifier = Modifier.height(128.dp)) - - BisqAmountSelector( - presenter.quoteCurrencyCode, - presenter.formattedMinAmountWithCode, - presenter.formattedMaxAmountWithCode, - presenter.sliderPosition, - presenter.formattedQuoteAmount, - presenter.formattedBaseAmount, - { sliderValue -> presenter.onSliderValueChanged(sliderValue) }, - { textInput -> presenter.onTextValueChanged(textInput) } - ) + Column( + modifier = Modifier.fillMaxHeight(), + verticalArrangement = Arrangement.Center, + ) { + BisqAmountSelector( + presenter.quoteCurrencyCode, + presenter.formattedMinAmountWithCode, + presenter.formattedMaxAmountWithCode, + presenter.sliderPosition, + presenter.formattedQuoteAmount, + presenter.formattedBaseAmount, + { sliderValue -> presenter.onSliderValueChanged(sliderValue) }, + { textInput -> presenter.onTextValueChanged(textInput) } + ) + } } } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt index d3f69cc8..4ad218e9 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodPresenter.kt @@ -1,5 +1,6 @@ package network.bisq.mobile.presentation.ui.uicases.trade.take_offer +import kotlinx.coroutines.flow.MutableStateFlow import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes @@ -15,6 +16,7 @@ class TakeOfferPaymentMethodPresenter( lateinit var baseSidePaymentMethods: List var quoteSidePaymentMethod: String? = null var baseSidePaymentMethod: String? = null + var quoteCurrencyCode: String = "USD" private lateinit var takeOfferModel: TakeOfferPresenter.TakeOfferModel @@ -32,6 +34,8 @@ class TakeOfferPaymentMethodPresenter( if (offerListItem.baseSidePaymentMethods.size == 1) { baseSidePaymentMethod = offerListItem.baseSidePaymentMethods[0] } + + quoteCurrencyCode = takeOfferModel.priceQuote.market.quoteCurrencyCode } fun onQuoteSidePaymentMethodSelected(paymentMethod: String) { @@ -72,4 +76,29 @@ class TakeOfferPaymentMethodPresenter( } private fun isValid() = quoteSidePaymentMethod != null && baseSidePaymentMethod != null + + fun getPaymentMethodAsSet(paymentMethod: String?): MutableStateFlow> { + return if (paymentMethod == null) + MutableStateFlow(emptySet()) + else { + MutableStateFlow(setOf(paymentMethod)) + } + } + + fun getQuoteSidePaymentMethodsImagePaths(): List { + return quoteSidePaymentMethods.map { payment -> + getPaymentMethodImagePath(payment, "fiat") + } + } + + fun getBaseSidePaymentMethodsImagePaths(): List { + return baseSidePaymentMethods.map { payment -> + getPaymentMethodImagePath(payment, "bitcoin") + } + } + + private fun getPaymentMethodImagePath(paymentMethod: String, directory: String): String { + val fileName = paymentMethod.lowercase().replace("-", "_") + return "drawable/payment/$directory/$fileName.png" + } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt index 13026200..35ceccae 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt @@ -19,11 +19,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp import cafe.adriel.lyricist.LocalStrings +import kotlinx.coroutines.flow.MutableStateFlow import network.bisq.mobile.i18n.toDisplayString import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.DynamicImage +import network.bisq.mobile.presentation.ui.components.atoms.PaymentTypeCard import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.components.layout.MultiScreenWizardScaffold +import network.bisq.mobile.presentation.ui.components.molecules.BisqPaymentToggle +import network.bisq.mobile.presentation.ui.components.organisms.PaymentMethodCard import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme import network.bisq.mobile.presentation.ui.theme.BisqUIConstants @@ -32,19 +36,18 @@ import org.koin.compose.koinInject @Composable fun TakeOfferPaymentMethodScreen() { val strings = LocalStrings.current.bisqEasy - val paymentMethodStrings = LocalStrings.current.paymentMethod val presenter: TakeOfferPaymentMethodPresenter = koinInject() val baseSidePaymentMethod = remember { mutableStateOf(presenter.baseSidePaymentMethod) } val quoteSidePaymentMethod = remember { mutableStateOf(presenter.quoteSidePaymentMethod) } + val quoteCurrencyCode = remember { mutableStateOf(presenter.quoteCurrencyCode) } RememberPresenterLifecycle(presenter, { baseSidePaymentMethod.value = presenter.baseSidePaymentMethod quoteSidePaymentMethod.value = presenter.quoteSidePaymentMethod + quoteCurrencyCode.value = presenter.quoteCurrencyCode }) - var customMethodCounter = 1 - MultiScreenWizardScaffold( strings.bisqEasy_takeOffer_progress_method, stepIndex = 2, @@ -60,112 +63,39 @@ fun TakeOfferPaymentMethodScreen() { ) if (presenter.hasMultipleQuoteSidePaymentMethods) { + BisqGap.V2() - BisqGap.V2() - Column( - modifier = Modifier.padding(horizontal = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - BisqText.largeLight( - text = strings.bisqEasy_takeOffer_paymentMethods_subtitle_fiat_buyer("USD"), - color = BisqTheme.colors.grey2 - ) - BisqGap.V2() - Column( - modifier = Modifier.fillMaxWidth().padding(horizontal = 38.dp), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(BisqUIConstants.ScreenPadding) - ) { - presenter.quoteSidePaymentMethods.forEach { paymentMethod -> - // TODO: Make this to Toggle buttons. Can get paymentMethod as some Enum? + PaymentMethodCard( + title = strings.bisqEasy_takeOffer_paymentMethods_subtitle_fiat_buyer(quoteCurrencyCode.value), + imagePaths = presenter.getQuoteSidePaymentMethodsImagePaths(), + availablePaymentMethods = presenter.quoteSidePaymentMethods, + i18n = LocalStrings.current.paymentMethod, + selectedPaymentMethods = presenter.getPaymentMethodAsSet(quoteSidePaymentMethod.value), + onToggle = { paymentMethod -> + quoteSidePaymentMethod.value = paymentMethod + presenter.onQuoteSidePaymentMethodSelected(paymentMethod) + }, + ) - val isSelected = paymentMethod == quoteSidePaymentMethod.value - val backgroundColor by animateColorAsState( - targetValue = if (isSelected) BisqTheme.colors.primary else BisqTheme.colors.dark5 - ) - Row( - modifier = Modifier - .fillMaxWidth() - .clip(shape = RoundedCornerShape(6.dp)) - .background(color = backgroundColor) - .clickable { - quoteSidePaymentMethod.value = paymentMethod - presenter.onQuoteSidePaymentMethodSelected(paymentMethod) - } - .padding(start = 18.dp) - .padding(vertical = 10.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(10.dp) - ) - { - DynamicImage( - path = "drawable/payment/fiat/${ - paymentMethod - .lowercase() - .replace("-", "_") - }.png", - fallbackPath = "drawable/payment/fiat/custom_payment_${customMethodCounter++}.png", - modifier = Modifier.size(15.dp), - ) - BisqText.baseRegular(text = paymentMethodStrings.toDisplayString(paymentMethod)) - } - } - } - } } if (presenter.hasMultipleBaseSidePaymentMethods) { + BisqGap.V2() - BisqGap.V2() - Column( - modifier = Modifier.padding(horizontal = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - BisqText.largeLight( - text = strings.bisqEasy_takeOffer_paymentMethods_subtitle_bitcoin_seller, - color = BisqTheme.colors.grey2 - ) - BisqGap.V1() - Column( - modifier = Modifier.fillMaxWidth().padding(horizontal = 38.dp), - horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.spacedBy(BisqUIConstants.ScreenPadding) - ) { - presenter.baseSidePaymentMethods.forEach { paymentMethod -> - // TODO: Make this to Toggle buttons. Can get paymentMethod as some Enum? - val isSelected = paymentMethod == baseSidePaymentMethod.value - val backgroundColor by animateColorAsState( - targetValue = if (isSelected) BisqTheme.colors.primary else BisqTheme.colors.dark5 - ) - Row( - modifier = Modifier - .fillMaxWidth() - .clip(shape = RoundedCornerShape(6.dp)) - .background(color = backgroundColor) - .clickable { - baseSidePaymentMethod.value = paymentMethod - presenter.onBaseSidePaymentMethodSelected(paymentMethod) - } - .padding(horizontal = 10.dp) - .padding(vertical = 10.dp), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(10.dp) - ) { - DynamicImage( - "drawable/payment/bitcoin/${ - paymentMethod - .lowercase() - .replace("-", "_") - }.png", - modifier = Modifier.size(15.dp) - ) - BisqText.baseRegular(text = paymentMethodStrings.toDisplayString(paymentMethod)) - } - } - } - } + PaymentMethodCard( + title = strings.bisqEasy_takeOffer_paymentMethods_subtitle_bitcoin_seller, + imagePaths = presenter.getBaseSidePaymentMethodsImagePaths(), + availablePaymentMethods = presenter.baseSidePaymentMethods, + i18n = LocalStrings.current.paymentMethod, + selectedPaymentMethods = presenter.getPaymentMethodAsSet(baseSidePaymentMethod.value), + onToggle = { paymentMethod -> + baseSidePaymentMethod.value = paymentMethod + presenter.onBaseSidePaymentMethodSelected(paymentMethod) + }, + ) + } } } \ No newline at end of file diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewScreen.kt index cfce0e30..34d22b85 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewScreen.kt @@ -57,7 +57,7 @@ fun TakeOfferReviewTradeScreen() { } BisqHDivider() - Column(verticalArrangement = Arrangement.spacedBy(24.dp)) { + Column(verticalArrangement = Arrangement.spacedBy(BisqUIConstants.ScreenPadding2X)) { InfoBox( label = strings.bisqEasy_tradeWizard_review_priceDescription_taker, valueComposable = { From 8dfa0e45845155068b4c731c64b2793ea0160d1b Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Wed, 1 Jan 2025 22:40:11 +0530 Subject: [PATCH 14/16] - Fixed compile time issues --- .../TakeOfferPaymentMethodScreen.kt | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt index 35ceccae..e6481ad4 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferPaymentMethodScreen.kt @@ -1,36 +1,15 @@ package network.bisq.mobile.presentation.ui.uicases.trade.take_offer -import androidx.compose.animation.animateColorAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.unit.dp import cafe.adriel.lyricist.LocalStrings -import kotlinx.coroutines.flow.MutableStateFlow -import network.bisq.mobile.i18n.toDisplayString import network.bisq.mobile.presentation.ui.components.atoms.BisqText -import network.bisq.mobile.presentation.ui.components.atoms.DynamicImage -import network.bisq.mobile.presentation.ui.components.atoms.PaymentTypeCard import network.bisq.mobile.presentation.ui.components.atoms.layout.BisqGap import network.bisq.mobile.presentation.ui.components.layout.MultiScreenWizardScaffold -import network.bisq.mobile.presentation.ui.components.molecules.BisqPaymentToggle import network.bisq.mobile.presentation.ui.components.organisms.PaymentMethodCard import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme -import network.bisq.mobile.presentation.ui.theme.BisqUIConstants import org.koin.compose.koinInject @Composable From 5b5b1bfe18573d7d82bc02326458ae22a7448f5a Mon Sep 17 00:00:00 2001 From: nostrbuddha Date: Wed, 8 Jan 2025 00:29:21 +0530 Subject: [PATCH 15/16] [Fix] Back navigation --- .../presentation/ui/components/molecules/TopBar.kt | 10 +++++++++- .../presentation/ui/uicases/TabContainerScreen.kt | 14 ++++++++++++++ .../create_offer/CreateOfferReviewPresenter.kt | 2 +- .../ui/uicases/startup/CreateProfilePresenter.kt | 2 +- .../trade/take_offer/TakeOfferReviewPresenter.kt | 2 +- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt index 7da733ab..8e13d363 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt @@ -45,6 +45,7 @@ fun TopBar( isHome: Boolean = false, customBackButton: @Composable (() -> Unit)? = null, backConfirmation: Boolean = false, + backBehavior: (() -> Unit)? = null, isFlowScreen: Boolean = false, stepText: String = "" ) { @@ -138,8 +139,15 @@ fun TopBar( }, ) + // TODO: What if both backBehavior and backConfirmation are set + if (backBehavior != null) { + BackHandler(onBackPressed = { + backBehavior.invoke() + }) + } + if (backConfirmation) { - BackHandler( onBackPressed = { + BackHandler(onBackPressed = { showBackConfirmationDialog = true }) } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt index 08307d45..d24a8851 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/TabContainerScreen.kt @@ -52,6 +52,20 @@ fun TabContainerScreen() { Routes.TabSettings.name -> "Settings" else -> "App" }, + backBehavior = { + if (currentRoute != Routes.TabHome.name) { + navController.navigate(Routes.TabHome.name) { + navController.graph.startDestinationRoute?.let { route -> + popUpTo(route) { saveState = false } + } + launchSingleTop = true + restoreState = false + } + } else { + presenter.showSnackbar("Press back again to exit") + presenter.goBack() + } + } ) }, diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferReviewPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferReviewPresenter.kt index 773fb4da..d791c460 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferReviewPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offer/create_offer/CreateOfferReviewPresenter.kt @@ -116,6 +116,6 @@ class CreateOfferReviewPresenter( } fun onGoToOfferList() { - rootNavigator.navigate(Routes.Offerbook.name) + rootNavigator.popBackStack(Routes.Offerbook.name, false, false) } } diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt index b7be29e9..bb0c86ca 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt @@ -102,7 +102,7 @@ open class CreateProfilePresenter( popUpTo(Routes.CreateProfile.name) { inclusive = true } } */ rootNavigator.navigate(Routes.TabContainer.name) { - popUpTo(Routes.CreateProfile.name) { inclusive = true } + popUpTo(Routes.Onboarding.name) { inclusive = true } } }.onFailure { e -> // TODO give user feedback (we could have a general error screen covering usual diff --git a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt index 380c7dc4..50cb9533 100644 --- a/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt +++ b/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trade/take_offer/TakeOfferReviewPresenter.kt @@ -112,7 +112,7 @@ class TakeOfferReviewPresenter( fun onGoToOpenTrades() { rootNavigator.navigate(Routes.TradeFlow.name) { - popUpTo(Routes.TakeOfferTradeAmount.name) { inclusive = true } + popUpTo(Routes.Offerbook.name) } } From b49c1b4a896a82d4dd1a1a33abd21b2c6d4dff5e Mon Sep 17 00:00:00 2001 From: Rodrigo Varela Date: Wed, 8 Jan 2025 09:07:44 +1100 Subject: [PATCH 16/16] - added potential implementation for ios BackHAndler commented for now as explained in the TODO --- .../ui/components/BackHandler.ios.kt | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt b/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt index fbe3715b..dc5005e4 100644 --- a/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt +++ b/shared/presentation/src/iosMain/kotlin/network/bisq/mobile/presentation/ui/components/BackHandler.ios.kt @@ -1,8 +1,42 @@ package network.bisq.mobile.presentation.ui.components import androidx.compose.runtime.Composable +//import androidx.compose.runtime.DisposableEffect +//import androidx.compose.ui.interop.LocalUIViewController +//import platform.UIKit.UINavigationController +//import platform.UIKit.UINavigationControllerDelegateProtocol +//import platform.UIKit.UIViewController +//import platform.UIKit.navigationController +//import platform.darwin.NSObject @Composable actual fun BackHandler(onBackPressed: () -> Unit) { - // TODO +// TODO for iOS there is no back button concept as in android, however when we do implement the back +// gesture handling we will need this. One option is something like the following: + +// val viewController = LocalUIViewController.current +// +// DisposableEffect(viewController) { +// val navigationController = viewController.navigationController +// +// val backPressHandler = object : NSObject(), UINavigationControllerDelegateProtocol { +// override fun navigationController( +// navigationController: UINavigationController, +// willShowViewController: UIViewController, +// animated: Boolean +// ) { +// if (navigationController.viewControllers.contains(viewController).not()) { +// onBackPressed() +// } +// } +// } +// +// navigationController?.delegate = backPressHandler +// +// onDispose { +// if (navigationController?.delegate == backPressHandler) { +// navigationController?.delegate = null +// } +// } +// } }