diff --git a/bisqapps/androidNode/build.gradle.kts b/bisqapps/androidNode/build.gradle.kts index a8e84bfb..53db9735 100644 --- a/bisqapps/androidNode/build.gradle.kts +++ b/bisqapps/androidNode/build.gradle.kts @@ -159,6 +159,7 @@ dependencies { implementation(libs.bisq.core.application) implementation(libs.bisq.core.chat) implementation(libs.bisq.core.presentation) + implementation(libs.bisq.core.bisq.easy) // protobuf implementation(libs.protobuf.gradle.plugin) diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt index b8ddb691..227dec2b 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/AndroidApplicationService.kt @@ -20,6 +20,7 @@ import androidx.core.util.Supplier import bisq.account.AccountService import bisq.application.ApplicationService import bisq.application.State +import bisq.bisq_easy.BisqEasyService import bisq.bonded_roles.BondedRolesService import bisq.bonded_roles.security_manager.alert.AlertNotificationsService import bisq.chat.ChatService @@ -43,7 +44,6 @@ import lombok.Setter import lombok.extern.slf4j.Slf4j import network.bisq.mobile.android.node.service.AndroidMemoryReportService import network.bisq.mobile.utils.Logging - import java.nio.file.Path import java.util.Optional import java.util.concurrent.CompletableFuture @@ -57,46 +57,51 @@ import java.util.concurrent.TimeUnit */ @Slf4j @Getter -class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportService, userDataDir: Path?) : +class AndroidApplicationService( + androidMemoryReportService: AndroidMemoryReportService, + userDataDir: Path? +) : ApplicationService("android", arrayOf(), userDataDir), Logging { @Getter - class Supplier { + class Provider { @Setter lateinit var applicationService: AndroidApplicationService - var stateSupplier: androidx.core.util.Supplier> = + var state: Supplier> = Supplier { applicationService.state } - var securityServiceSupplier: androidx.core.util.Supplier = + var securityService: Supplier = Supplier { applicationService.securityService } - var networkServiceSupplier: androidx.core.util.Supplier = + var networkService: Supplier = Supplier { applicationService.networkService } - var identityServiceSupplier: androidx.core.util.Supplier = + var identityService: Supplier = Supplier { applicationService.identityService } - var bondedRolesServiceSupplier: androidx.core.util.Supplier = + var bondedRolesService: Supplier = Supplier { applicationService.bondedRolesService } - var accountServiceSupplier: androidx.core.util.Supplier = + var accountService: Supplier = Supplier { applicationService.accountService } - var offerServiceSupplier: androidx.core.util.Supplier = + var offerService: Supplier = Supplier { applicationService.offerService } - var contractServiceSupplier: androidx.core.util.Supplier = + var contractService: Supplier = Supplier { applicationService.contractService } - var userServiceSupplier: androidx.core.util.Supplier = + var userService: Supplier = Supplier { applicationService.userService } - var chatServiceSupplier: androidx.core.util.Supplier = + var chatService: Supplier = Supplier { applicationService.chatService } - var settingsServiceSupplier: androidx.core.util.Supplier = + var settingsService: Supplier = Supplier { applicationService.settingsService } - var supportServiceSupplier: androidx.core.util.Supplier = + var bisqEasyService: Supplier = + Supplier { applicationService.bisqEasyService } + var supportService: Supplier = Supplier { applicationService.supportService } - var systemNotificationServiceSupplier: androidx.core.util.Supplier = + var systemNotificationService: Supplier = Supplier { applicationService.systemNotificationService } - var tradeServiceSupplier: androidx.core.util.Supplier = + var tradeService: Supplier = Supplier { applicationService.tradeService } - var alertNotificationsServiceSupplier: androidx.core.util.Supplier = + var alertNotificationsService: Supplier = Supplier { applicationService.alertNotificationsService } - var favouriteMarketsServiceSupplier: androidx.core.util.Supplier = + var favouriteMarketsService: Supplier = Supplier { applicationService.favouriteMarketsService } - var dontShowAgainServiceSupplier: androidx.core.util.Supplier = + var dontShowAgainService: Supplier = Supplier { applicationService.dontShowAgainService } } @@ -147,11 +152,11 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS val supportService: SupportService val systemNotificationService = SystemNotificationService(Optional.empty()) val tradeService: TradeService + val bisqEasyService: BisqEasyService val alertNotificationsService: AlertNotificationsService val favouriteMarketsService: FavouriteMarketsService val dontShowAgainService: DontShowAgainService - init { chatService = ChatService( persistenceService, @@ -183,6 +188,22 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS settingsService ) + bisqEasyService = BisqEasyService( + persistenceService, + securityService, + networkService, + identityService, + bondedRolesService, + accountService, + offerService, + contractService, + userService, + chatService, + settingsService, + supportService, + systemNotificationService, + tradeService + ) alertNotificationsService = AlertNotificationsService(settingsService, bondedRolesService.alertService) @@ -195,11 +216,11 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS override fun initialize(): CompletableFuture { var ts = System.currentTimeMillis() pruneAllBackups().join() - log.i("pruneAllBackups took $(System.currentTimeMillis() - ts) ms", ) + log.i("pruneAllBackups took ${(System.currentTimeMillis() - ts)} ms") ts = System.currentTimeMillis() readAllPersisted().join() - log.i("readAllPersisted took $(System.currentTimeMillis() - ts) ms") + log.i("readAllPersisted took ${(System.currentTimeMillis() - ts)} ms") return securityService.initialize() .thenCompose { result: Boolean? -> @@ -245,6 +266,10 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS } } + fun onStop() { + shutdown().join() + } + override fun shutdown(): CompletableFuture { log.i("shutdown") // We shut down services in opposite order as they are initialized @@ -333,7 +358,6 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS } } - private fun logError(throwable: Throwable): Boolean { log.e("Exception at shutdown", throwable) return false diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt index 22501320..5f29200c 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/di/AndroidNodeModule.kt @@ -2,13 +2,16 @@ package network.bisq.mobile.android.node.di import network.bisq.mobile.android.node.AndroidApplicationService import network.bisq.mobile.android.node.domain.bootstrap.NodeApplicationBootstrapFacade -import network.bisq.mobile.android.node.domain.data.repository.NodeGreetingRepository +import network.bisq.mobile.android.node.domain.market_price.NodeMarketPriceServiceFacade +import network.bisq.mobile.android.node.domain.offerbook.NodeOfferbookServiceFacade import network.bisq.mobile.android.node.domain.user_profile.NodeUserProfileServiceFacade import network.bisq.mobile.android.node.presentation.NodeMainPresenter import network.bisq.mobile.android.node.presentation.OnBoardingNodePresenter import network.bisq.mobile.android.node.service.AndroidMemoryReportService import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade +import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.AppPresenter import network.bisq.mobile.presentation.ui.uicases.startup.IOnboardingPresenter @@ -17,23 +20,22 @@ import org.koin.dsl.bind import org.koin.dsl.module val androidNodeModule = module { - // this one is for example properties, will be eliminated soon - single { NodeGreetingRepository() } - single { AndroidMemoryReportService(androidContext()) } - single { AndroidApplicationService.Supplier() } + single { AndroidApplicationService.Provider() } single { NodeApplicationBootstrapFacade(get()) } - single { NodeUserProfileServiceFacade(get()) } + single { NodeMarketPriceServiceFacade(get()) } + single { NodeUserProfileServiceFacade(get()) } + single { NodeOfferbookServiceFacade(get(), get()) } // this line showcases both, the possibility to change behaviour of the app by changing one definition // and binding the same obj to 2 different abstractions - single { NodeMainPresenter(get(), get(), get()) } bind AppPresenter::class + single { NodeMainPresenter(get(), get(), get(), get(), get()) } bind AppPresenter::class single { OnBoardingNodePresenter(get()) } bind IOnboardingPresenter::class } \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt index 62af1fc0..b054e958 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/bootstrap/NodeApplicationBootstrapFacade.kt @@ -1,25 +1,35 @@ package network.bisq.mobile.android.node.domain.bootstrap import bisq.application.State +import bisq.common.observable.Observable +import bisq.common.observable.Pin import network.bisq.mobile.android.node.AndroidApplicationService import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade class NodeApplicationBootstrapFacade( - private val supplier: AndroidApplicationService.Supplier + private val applicationService: AndroidApplicationService.Provider ) : ApplicationBootstrapFacade() { - override fun initialize() { - supplier.stateSupplier.get().addObserver { state: State -> + // Dependencies + private val applicationServiceState: Observable by lazy { + applicationService.state.get() + } + + // Misc + private var applicationServiceStatePin: Pin? = null + + override fun activate() { + applicationServiceStatePin = applicationServiceState.addObserver { state: State -> when (state) { State.INITIALIZE_APP -> { - setState("Starting Bisq") - setProgress(0f) + setState("Starting Bisq") + setProgress(0f) } State.INITIALIZE_NETWORK -> { - setState("Initialize P2P network") - setProgress(0.5f) + setState("Initialize P2P network") + setProgress(0.5f) } // not used @@ -27,20 +37,25 @@ class NodeApplicationBootstrapFacade( } State.INITIALIZE_SERVICES -> { - setState("Initialize services") - setProgress(0.75f) + setState("Initialize services") + setProgress(0.75f) } State.APP_INITIALIZED -> { - setState("Bisq started") - setProgress(1f) + setState("Bisq started") + setProgress(1f) } State.FAILED -> { - setState("Startup failed") - setProgress(0f) + setState("Startup failed") + setProgress(0f) } } } } + + override fun deactivate() { + applicationServiceStatePin?.unbind() + applicationServiceStatePin = null + } } \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/market_price/NodeMarketPriceServiceFacade.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/market_price/NodeMarketPriceServiceFacade.kt new file mode 100644 index 00000000..f09788bd --- /dev/null +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/market_price/NodeMarketPriceServiceFacade.kt @@ -0,0 +1,71 @@ +package network.bisq.mobile.android.node.domain.market_price + +import bisq.bonded_roles.market_price.MarketPriceService +import bisq.common.observable.Pin +import bisq.presentation.formatters.PriceFormatter +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.android.node.AndroidApplicationService +import network.bisq.mobile.android.node.domain.offerbook.NodeOfferbookServiceFacade.Companion.toLibraryMarket +import network.bisq.mobile.android.node.domain.offerbook.NodeOfferbookServiceFacade.Companion.toReplicatedMarket +import network.bisq.mobile.domain.data.model.market_price.MarketPriceItem +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.utils.Logging + +class NodeMarketPriceServiceFacade(private val applicationService: AndroidApplicationService.Provider) : + MarketPriceServiceFacade, Logging { + + // Dependencies + private val marketPriceService: MarketPriceService by lazy { + applicationService.bondedRolesService.get().marketPriceService + } + + // Properties + private val _marketPriceItem = MutableStateFlow(MarketPriceItem.EMPTY) + override val marketPriceItem: StateFlow get() = _marketPriceItem + + // Misc + private var selectedMarketPin: Pin? = null + private var marketPricePin: Pin? = null + + // Life cycle + override fun activate() { + observeSelectedMarket() + observeMarketPrice() + } + + override fun deactivate() { + selectedMarketPin?.unbind() + selectedMarketPin = null + marketPricePin?.unbind() + marketPricePin = null + } + + // API + override fun selectMarket(marketListItem: MarketListItem) { + marketPriceService.setSelectedMarket(toLibraryMarket(marketListItem)) + } + + // Private + private fun observeMarketPrice() { + marketPricePin = marketPriceService.marketPriceByCurrencyMap.addObserver { updatePrice() } + } + + private fun observeSelectedMarket() { + selectedMarketPin?.unbind() + selectedMarketPin = marketPriceService.selectedMarket.addObserver { market -> + _marketPriceItem.value = MarketPriceItem(toReplicatedMarket(market)) + updatePrice() + } + } + + private fun updatePrice() { + marketPriceService.findMarketPriceQuote(marketPriceService.selectedMarket.get()) + .ifPresent { priceQuote -> + _marketPriceItem.value.setQuote(priceQuote.value) + val formattedPrice = PriceFormatter.format(priceQuote) + _marketPriceItem.value.setFormattedPrice(formattedPrice) + } + } +} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/NodeOfferbookServiceFacade.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/NodeOfferbookServiceFacade.kt new file mode 100644 index 00000000..73220e22 --- /dev/null +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/NodeOfferbookServiceFacade.kt @@ -0,0 +1,71 @@ +package network.bisq.mobile.android.node.domain.offerbook + +import bisq.common.currency.Market +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.android.node.AndroidApplicationService +import network.bisq.mobile.android.node.domain.offerbook.market.NodeMarketListItemService +import network.bisq.mobile.android.node.domain.offerbook.market.NodeSelectedOfferbookMarketService +import network.bisq.mobile.android.node.domain.offerbook.offer.NodeOfferbookListItemService +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.domain.data.model.offerbook.market.OfferbookMarket +import network.bisq.mobile.utils.Logging + +class NodeOfferbookServiceFacade( + applicationService: AndroidApplicationService.Provider, + private val marketPriceServiceFacade: MarketPriceServiceFacade +) : + OfferbookServiceFacade, Logging { + + companion object { + fun toLibraryMarket(marketListItem: MarketListItem) = + Market( + marketListItem.market.baseCurrencyCode, + marketListItem.market.quoteCurrencyCode, + marketListItem.market.baseCurrencyName, + marketListItem.market.quoteCurrencyName + ) + + fun toReplicatedMarket(market: Market) = + network.bisq.mobile.client.replicated_model.common.currency.Market( + market.baseCurrencyCode, + market.quoteCurrencyCode, + market.baseCurrencyName, + market.quoteCurrencyName + ) + } + // Properties + override val offerbookMarketItems: List get() = marketListItemService.marketListItems + override val offerListItems: StateFlow> get() = offerbookListItemService.offerListItems + override val selectedOfferbookMarket: StateFlow get() = selectedOfferbookMarketService.selectedOfferbookMarket + + // Misc + private val offerbookListItemService: NodeOfferbookListItemService = + NodeOfferbookListItemService(applicationService) + private val marketListItemService: NodeMarketListItemService = + NodeMarketListItemService(applicationService) + private val selectedOfferbookMarketService: NodeSelectedOfferbookMarketService = + NodeSelectedOfferbookMarketService(applicationService, marketPriceServiceFacade) + + // Life cycle + override fun activate() { + marketListItemService.activate() + selectedOfferbookMarketService.activate() + offerbookListItemService.activate() + } + + override fun deactivate() { + marketListItemService.deactivate() + selectedOfferbookMarketService.deactivate() + offerbookListItemService.deactivate() + } + + // API + override fun selectMarket(marketListItem: MarketListItem) { + selectedOfferbookMarketService.selectMarket(toLibraryMarket(marketListItem)) + //todo marketPriceServiceFacade should not be managed here but on a higher level or from the presenter + marketPriceServiceFacade.selectMarket(marketListItem) + } +} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/market/NodeMarketListItemService.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/market/NodeMarketListItemService.kt new file mode 100644 index 00000000..3682934d --- /dev/null +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/market/NodeMarketListItemService.kt @@ -0,0 +1,96 @@ +package network.bisq.mobile.android.node.domain.offerbook.market + +import bisq.bonded_roles.market_price.MarketPriceService +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannel +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage +import bisq.common.observable.Pin +import network.bisq.mobile.android.node.AndroidApplicationService +import network.bisq.mobile.android.node.domain.offerbook.NodeOfferbookServiceFacade.Companion.toLibraryMarket +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.utils.Logging + +class NodeMarketListItemService(private val applicationService: AndroidApplicationService.Provider) : + LifeCycleAware, Logging { + + // Dependencies + private val marketPriceService: MarketPriceService by lazy { + applicationService.bondedRolesService.get().marketPriceService + } + private val bisqEasyOfferbookChannelService: BisqEasyOfferbookChannelService by lazy { + applicationService.chatService.get().bisqEasyOfferbookChannelService + } + + // Properties + private val _marketListItems: List by lazy { fillMarketListItems() } + val marketListItems: List get() = _marketListItems + + // Misc + private var numOffersObservers: MutableList = mutableListOf() + + // Life cycle + override fun activate() { + numOffersObservers.forEach { it.resume() } + } + + override fun deactivate() { + numOffersObservers.forEach { it.dispose() } + } + + // Private + private fun fillMarketListItems(): MutableList { + val offerbookMarketItems: MutableList = mutableListOf() + bisqEasyOfferbookChannelService.channels + .forEach { channel -> + val market = Market( + channel.market.baseCurrencyCode, + channel.market.quoteCurrencyCode, + channel.market.baseCurrencyName, + channel.market.quoteCurrencyName, + ) + + // We convert channel.market to our replicated Market model + val offerbookMarketItem = MarketListItem(market) + + val libraryMarket = toLibraryMarket(offerbookMarketItem) + if(marketPriceService.marketPriceByCurrencyMap.isEmpty() || + marketPriceService.marketPriceByCurrencyMap.containsKey(libraryMarket)){ + offerbookMarketItems.add(offerbookMarketItem) + val numOffersObserver = NumOffersObserver(channel, offerbookMarketItem::setNumOffers) + numOffersObservers.add(numOffersObserver) + } + } + return offerbookMarketItems + } + + // Inner class + inner class NumOffersObserver( + private val channel: BisqEasyOfferbookChannel, + val setNumOffers: (Int) -> Unit + ) { + private var channelPin: Pin? = null + + init { + channelPin = channel.chatMessages.addObserver { this.updateNumOffers() } + } + + fun resume() { + dispose() + channelPin = channel.chatMessages.addObserver { this.updateNumOffers() } + } + + fun dispose() { + channelPin?.unbind() + channelPin = null + } + + private fun updateNumOffers() { + val numOffers = channel.chatMessages.stream() + .filter { obj: BisqEasyOfferbookMessage -> obj.hasBisqEasyOffer() } + .count().toInt() + setNumOffers(numOffers) + } + } +} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/market/NodeSelectedOfferbookMarketService.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/market/NodeSelectedOfferbookMarketService.kt new file mode 100644 index 00000000..dadf97fd --- /dev/null +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/market/NodeSelectedOfferbookMarketService.kt @@ -0,0 +1,98 @@ +package network.bisq.mobile.android.node.domain.offerbook.market + +import bisq.bonded_roles.market_price.MarketPriceService +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannel +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannelService +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookSelectionService +import bisq.common.currency.Market +import bisq.common.observable.Pin +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.android.node.AndroidApplicationService +import network.bisq.mobile.android.node.domain.offerbook.NodeOfferbookServiceFacade.Companion.toReplicatedMarket +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.market.OfferbookMarket +import network.bisq.mobile.utils.Logging + + +class NodeSelectedOfferbookMarketService( + private val applicationService: AndroidApplicationService.Provider, + private val marketPriceServiceFacade: MarketPriceServiceFacade +) : LifeCycleAware, Logging { + + // Dependencies + private val bisqEasyOfferbookChannelService: BisqEasyOfferbookChannelService by lazy { + applicationService.chatService.get().bisqEasyOfferbookChannelService + } + private val bisqEasyOfferbookChannelSelectionService: BisqEasyOfferbookSelectionService by lazy { + applicationService.chatService.get().bisqEasyOfferbookChannelSelectionService + } + private val marketPriceService: MarketPriceService by lazy { + applicationService.bondedRolesService.get().marketPriceService + } + + // Properties + private val _selectedOfferbookMarket = MutableStateFlow(OfferbookMarket.EMPTY) + val selectedOfferbookMarket: StateFlow get() = _selectedOfferbookMarket + + // Misc + private var selectedChannel: BisqEasyOfferbookChannel? = null + private var selectedChannelPin: Pin? = null + private var marketPricePin: Pin? = null + + // Life cycle + override fun activate() { + observeSelectedChannel() + observeMarketPrice() + } + + override fun deactivate() { + selectedChannelPin?.unbind() + selectedChannelPin = null + marketPricePin?.unbind() + marketPricePin = null + } + + // API + fun selectMarket(market: Market) { + log.i { "selectMarket " + market } + bisqEasyOfferbookChannelService.findChannel(market).ifPresent { + bisqEasyOfferbookChannelSelectionService.selectChannel(it) + } + } + + // Private + private fun observeMarketPrice() { + marketPricePin = marketPriceService.marketPriceByCurrencyMap.addObserver({ + marketPriceService.findMarketPriceQuote(marketPriceService.selectedMarket.get()) + updateMarketPrice() + }) + } + + private fun observeSelectedChannel() { + selectedChannelPin = + bisqEasyOfferbookChannelSelectionService.selectedChannel.addObserver { selectedChannel -> + this.selectedChannel = selectedChannel as BisqEasyOfferbookChannel + marketPriceService.setSelectedMarket(selectedChannel.market) + applySelectedOfferbookMarket() + } + } + + private fun applySelectedOfferbookMarket() { + if (selectedChannel == null) { + return + } + + val selectedChannel = selectedChannel!! + val market = toReplicatedMarket(selectedChannel.market) + _selectedOfferbookMarket.value = OfferbookMarket(market) + updateMarketPrice() + log.i { _selectedOfferbookMarket.value.toString() } + } + + private fun updateMarketPrice() { + val formattedPrice = marketPriceServiceFacade.marketPriceItem.value.formattedPrice + _selectedOfferbookMarket.value.setFormattedPrice(formattedPrice.value) + } +} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/offer/NodeOfferbookListItemService.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/offer/NodeOfferbookListItemService.kt new file mode 100644 index 00000000..cc8907e0 --- /dev/null +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/offerbook/offer/NodeOfferbookListItemService.kt @@ -0,0 +1,213 @@ +package network.bisq.mobile.android.node.domain.offerbook.offer + +import bisq.bonded_roles.market_price.MarketPriceService +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookChannel +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookMessage +import bisq.chat.bisqeasy.offerbook.BisqEasyOfferbookSelectionService +import bisq.common.currency.Market +import bisq.common.observable.Pin +import bisq.common.observable.collection.CollectionObserver +import bisq.common.observable.collection.ObservableSet +import bisq.common.util.StringUtils +import bisq.i18n.Res +import bisq.offer.Direction +import bisq.offer.amount.OfferAmountFormatter +import bisq.offer.amount.spec.AmountSpec +import bisq.offer.amount.spec.RangeAmountSpec +import bisq.offer.bisq_easy.BisqEasyOffer +import bisq.offer.payment_method.PaymentMethodSpecUtil +import bisq.offer.price.spec.PriceSpec +import bisq.offer.price.spec.PriceSpecFormatter +import bisq.presentation.formatters.DateFormatter +import bisq.user.identity.UserIdentityService +import bisq.user.profile.UserProfile +import bisq.user.profile.UserProfileService +import bisq.user.reputation.ReputationService +import com.google.common.base.Joiner +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.android.node.AndroidApplicationService +import network.bisq.mobile.client.replicated_model.user.reputation.ReputationScore +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem +import network.bisq.mobile.utils.Logging +import java.text.DateFormat +import java.util.Date +import java.util.Optional + + +class NodeOfferbookListItemService(private val applicationService: AndroidApplicationService.Provider) : + LifeCycleAware, Logging { + + // Dependencies + private val marketPriceService: MarketPriceService by lazy { + applicationService.bondedRolesService.get().marketPriceService + } + private val userProfileService: UserProfileService by lazy { + applicationService.userService.get().userProfileService + } + private val userIdentityService: UserIdentityService by lazy { + applicationService.userService.get().userIdentityService + } + private val reputationService: ReputationService by lazy { + applicationService.userService.get().reputationService + } + private val bisqEasyOfferbookChannelSelectionService: BisqEasyOfferbookSelectionService by lazy { + applicationService.chatService.get().bisqEasyOfferbookChannelSelectionService + } + + // Properties + private val _offerListItems = MutableStateFlow>(emptyList()) + val offerListItems: StateFlow> get() = _offerListItems + + // Misc + private var chatMessagesPin: Pin? = null + private var selectedChannelPin: Pin? = null + + + // Life cycle + override fun activate() { + addSelectedChannelObservers() + } + + override fun deactivate() { + chatMessagesPin?.unbind() + chatMessagesPin = null + + selectedChannelPin?.unbind() + selectedChannelPin = null + } + + // Private + private fun addSelectedChannelObservers() { + selectedChannelPin = + bisqEasyOfferbookChannelSelectionService.selectedChannel.addObserver { channel -> + if (channel is BisqEasyOfferbookChannel) { + addChatMessagesObservers(channel) + } + } + } + + private fun addChatMessagesObservers(marketChannel: BisqEasyOfferbookChannel) { + chatMessagesPin?.unbind() + _offerListItems.value = emptyList() + + val chatMessages: ObservableSet = marketChannel.chatMessages + chatMessagesPin = + chatMessages.addObserver(object : CollectionObserver { + override fun add(message: BisqEasyOfferbookMessage) { + if (message.hasBisqEasyOffer()) { + val offerListItem: OfferListItem = createOfferItem(message) + _offerListItems.value = _offerListItems.value + offerListItem + log.i { "add offer $offerListItem" } + } + } + + override fun remove(message: Any) { + if (message is BisqEasyOfferbookMessage && message.hasBisqEasyOffer()) { + val offerListItem = + _offerListItems.value.first { it.messageId == message.id } + _offerListItems.value = _offerListItems.value - offerListItem + log.i { "remove offer $offerListItem" } + } + } + + override fun clear() { + _offerListItems.value = emptyList() + } + }) + } + + private fun createOfferItem(message: BisqEasyOfferbookMessage): OfferListItem { + val bisqEasyOffer: BisqEasyOffer = message.bisqEasyOffer.get() + val date = message.date + val formattedDate = DateFormatter.formatDateTime( + Date(date), DateFormat.MEDIUM, DateFormat.SHORT, + true, " " + Res.get("temporal.at") + " " + ) + + val authorUserProfileId = message.authorUserProfileId + val senderUserProfile: Optional = + userProfileService.findUserProfile(authorUserProfileId) + val nym: String = senderUserProfile.map { it.nym }.orElse("") + val userName: String = senderUserProfile.map { it.userName }.orElse("") + val reputationScore = + senderUserProfile.flatMap(reputationService::findReputationScore) + .map { + ReputationScore( + it.totalScore, + it.fiveSystemScore, + it.ranking + ) + } + .orElse(ReputationScore.NONE) + val amountSpec: AmountSpec = bisqEasyOffer.amountSpec + val priceSpec: PriceSpec = bisqEasyOffer.priceSpec + val hasAmountRange = amountSpec is RangeAmountSpec + val market: Market = bisqEasyOffer.market + val formattedQuoteAmount: String = + OfferAmountFormatter.formatQuoteAmount( + marketPriceService, + amountSpec, + priceSpec, + market, + hasAmountRange, + true + ) + val formattedPrice: String = PriceSpecFormatter.getFormattedPriceSpec(priceSpec, true) + + val quoteSidePaymentMethods: List = + PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.quoteSidePaymentMethodSpecs) + .map { it.name } + .toList() + val baseSidePaymentMethods: List = + PaymentMethodSpecUtil.getPaymentMethods(bisqEasyOffer.baseSidePaymentMethodSpecs) + .map { it.name } + .toList() + val supportedLanguageCodes: String = + Joiner.on(",").join(bisqEasyOffer.supportedLanguageCodes) + val isMyMessage = message.isMyMessage(userIdentityService) + val direction: network.bisq.mobile.client.replicated_model.offer.Direction = + if (bisqEasyOffer.direction.isBuy) { + network.bisq.mobile.client.replicated_model.offer.Direction.BUY + } else { + network.bisq.mobile.client.replicated_model.offer.Direction.SELL + } + + val offerTitle = getOfferTitle(message, isMyMessage) + val messageId = message.id + val offerId = bisqEasyOffer.id + val offerListItem = OfferListItem( + messageId, + offerId, + isMyMessage, + direction, + offerTitle, + date, + formattedDate, + nym, + userName, + reputationScore, + formattedQuoteAmount, + formattedPrice, + quoteSidePaymentMethods, + baseSidePaymentMethods, + supportedLanguageCodes + ) + return offerListItem + } + + private fun getOfferTitle(message: BisqEasyOfferbookMessage, isMyMessage: Boolean): String { + if (isMyMessage) { + val direction: Direction = message.bisqEasyOffer.get().direction + val directionString: String = + StringUtils.capitalize(Res.get("offer." + direction.name.lowercase())) + return Res.get( + "bisqEasy.tradeWizard.review.chatMessage.myMessageTitle", + directionString + ) + } else { + return message.text + } + } +} \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt index 42e7fe65..8e90c3e0 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/domain/user_profile/NodeUserProfileServiceFacade.kt @@ -8,9 +8,8 @@ import bisq.user.UserService import bisq.user.identity.NymIdGenerator import bisq.user.profile.UserProfile import network.bisq.mobile.android.node.AndroidApplicationService -import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.utils.Logging - import java.security.KeyPair import java.util.Random import kotlin.math.max @@ -22,24 +21,28 @@ import kotlin.math.min * It uses in a in-memory model for the relevant data required for the presenter to reflect the domains state. * Persistence is done inside the Bisq 2 libraries. */ -class NodeUserProfileServiceFacade(private val supplier: AndroidApplicationService.Supplier) : +class NodeUserProfileServiceFacade(private val applicationService: AndroidApplicationService.Provider) : UserProfileServiceFacade, Logging { companion object { private const val AVATAR_VERSION = 0 } + // Dependencies + private val securityService: SecurityService by lazy { + applicationService.securityService.get() + } + private val userService: UserService by lazy { + applicationService.userService.get() + } + + // Misc private var pubKeyHash: ByteArray? = null private var keyPair: KeyPair? = null private var proofOfWork: ProofOfWork? = null - private val securityService: SecurityService - get() = supplier.securityServiceSupplier.get() - - private val userService: UserService - get() = supplier.userServiceSupplier.get() - + // API override suspend fun hasUserProfile(): Boolean { return userService.userIdentityService.userIdentities.isNotEmpty() } @@ -91,6 +94,7 @@ class NodeUserProfileServiceFacade(private val supplier: AndroidApplicationServi result(userProfile?.nickName, userProfile?.nym, userProfile?.id) } + // Private private fun getSelectedUserProfile(): UserProfile? { return userService.userIdentityService.selectedUserIdentity?.userProfile } diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt index fef79640..e5ca47e4 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/presentation/NodeMainPresenter.kt @@ -4,26 +4,56 @@ import android.app.Activity import network.bisq.mobile.android.node.AndroidApplicationService import network.bisq.mobile.android.node.service.AndroidMemoryReportService import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade import network.bisq.mobile.presentation.MainPresenter class NodeMainPresenter( - private val supplier: AndroidApplicationService.Supplier, + private val provider: AndroidApplicationService.Provider, private val androidMemoryReportService: AndroidMemoryReportService, - applicationBootstrapFacade: ApplicationBootstrapFacade -) : MainPresenter(applicationBootstrapFacade) { + private val applicationBootstrapFacade: ApplicationBootstrapFacade, + private val offerbookServiceFacade: OfferbookServiceFacade, + private val marketPriceServiceFacade: MarketPriceServiceFacade +) : MainPresenter() { - override fun initializeServices() { - log.i{"initializeServices1"} - val context = (view as Activity).applicationContext - val filesDirsPath = (view as Activity).filesDir.toPath() - supplier.applicationService = - AndroidApplicationService(androidMemoryReportService, filesDirsPath) - supplier.applicationService.initialize() - super.initializeServices() + private var applicationServiceCreated = false + override fun onViewAttached() { + super.onViewAttached() + if (!applicationServiceCreated) { + applicationServiceCreated = true + val filesDirsPath = (view as Activity).filesDir.toPath() + val applicationService = + AndroidApplicationService(androidMemoryReportService, filesDirsPath) + provider.applicationService = applicationService + + applicationBootstrapFacade.activate() + log.i { "Start initializing applicationService" } + applicationService.initialize() + .whenComplete { r: Boolean?, throwable: Throwable? -> + if (throwable == null) { + log.i { "ApplicationService initialized" } + applicationBootstrapFacade.deactivate() + offerbookServiceFacade.activate() + marketPriceServiceFacade.activate() + } else { + log.e("Initializing applicationService failed", throwable) + } + } + } else { + offerbookServiceFacade.activate() + marketPriceServiceFacade.activate() + } + } + + override fun onViewUnattaching() { + applicationBootstrapFacade.deactivate() + offerbookServiceFacade.deactivate() + marketPriceServiceFacade.deactivate() + super.onViewUnattaching() } override fun onDestroying() { - supplier.applicationService.shutdown() + provider.applicationService.onStop() super.onDestroying() } } \ No newline at end of file diff --git a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/service/AndroidMemoryReportService.kt b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/service/AndroidMemoryReportService.kt index c72d5d22..f0d049e9 100644 --- a/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/service/AndroidMemoryReportService.kt +++ b/bisqapps/androidNode/src/androidMain/kotlin/network/bisq/mobile/android/node/service/AndroidMemoryReportService.kt @@ -1,22 +1,24 @@ package network.bisq.mobile.android.node.service -import bisq.common.platform.MemoryReportService -import java.util.concurrent.CompletableFuture import android.app.ActivityManager import android.content.Context +import bisq.common.platform.MemoryReportService +import network.bisq.mobile.utils.Logging +import java.util.concurrent.CompletableFuture /** * Memory report for bisq jars calculations */ -class AndroidMemoryReportService(private val context: Context) : MemoryReportService { +class AndroidMemoryReportService(private val context: Context) : MemoryReportService, Logging { - private val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + private val activityManager = + context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager override fun logReport() { val usedMemory = usedMemoryInMB val freeMemory = freeMemoryInMB val totalMemory = totalMemoryInMB - println("Memory Report - Used: ${usedMemory}MB, Free: ${freeMemory}MB, Total: ${totalMemory}MB") + log.i("Memory Report - Used: ${usedMemory}MB, Free: ${freeMemory}MB, Total: ${totalMemory}MB") } override fun getUsedMemoryInBytes(): Long { diff --git a/bisqapps/gradle/libs.versions.toml b/bisqapps/gradle/libs.versions.toml index 28e56f6f..a8eb30c1 100644 --- a/bisqapps/gradle/libs.versions.toml +++ b/bisqapps/gradle/libs.versions.toml @@ -131,6 +131,7 @@ bisq-core-chat = { module = "bisq:chat", version.ref = "bisq-core" } bisq-core-contract = { module = "bisq:contract", version.ref = "bisq-core" } bisq-core-i18n = { module = "bisq:i18n", version.ref = "bisq-core" } bisq-core-identity = { module = "bisq:identity", version.ref = "bisq-core" } +bisq-core-bisq-easy = { module = "bisq:bisq-easy", version.ref = "bisq-core" } # bisq core transitive dependencies chimp-jsocks = { module = 'com.github.chimp1984:jsocks', version.ref = 'chimp-jsocks-lib' } diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt index 76ef94ac..966a621c 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/bootstrap/ClientApplicationBootstrapFacade.kt @@ -8,25 +8,27 @@ import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBoot class ClientApplicationBootstrapFacade() : ApplicationBootstrapFacade() { - private val coroutineScope = CoroutineScope(BackgroundDispatcher) - override fun initialize() { + override fun activate() { setState("Dummy state 1") setProgress(0f) // just dummy loading simulation, might be that there is no loading delay at the end... - coroutineScope.launch { - delay(500L) + CoroutineScope(BackgroundDispatcher).launch { + delay(50L) setState("Dummy state 2") setProgress(0.25f) - delay(500L) + delay(50L) setState("Dummy state 3") setProgress(0.5f) - delay(500L) + delay(50L) setState("Dummy state 4") setProgress(1f) } } + + override fun deactivate() { + } } \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt index 70f67302..6af40f42 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/di/ClientModule.kt @@ -8,11 +8,17 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.contextual import network.bisq.mobile.android.node.main.bootstrap.ClientApplicationBootstrapFacade +import network.bisq.mobile.client.market.ClientMarketPriceServiceFacade +import network.bisq.mobile.client.market.MarketPriceApiGateway +import network.bisq.mobile.client.offerbook.ClientOfferbookServiceFacade import network.bisq.mobile.client.service.ApiRequestService import network.bisq.mobile.domain.client.main.user_profile.ClientUserProfileServiceFacade +import network.bisq.mobile.client.offerbook.offer.OfferbookApiGateway import network.bisq.mobile.domain.client.main.user_profile.UserProfileApiGateway import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade -import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade +import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.utils.ByteArrayAsBase64Serializer import org.koin.core.qualifier.named import org.koin.dsl.module @@ -39,8 +45,15 @@ val clientModule = module { single(named("ApiBaseUrl")) { provideApiBaseUrl() } single { ApiRequestService(get(), get(named("ApiBaseUrl"))) } + + single { MarketPriceApiGateway(get()) } + single { ClientMarketPriceServiceFacade(get()) } + single { UserProfileApiGateway(get()) } single { ClientUserProfileServiceFacade(get()) } + + single { OfferbookApiGateway(get()) } + single { ClientOfferbookServiceFacade(get(), get()) } } fun provideApiBaseUrl(): String { diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/ClientMarketPriceServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/ClientMarketPriceServiceFacade.kt new file mode 100644 index 00000000..656dbbf2 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/ClientMarketPriceServiceFacade.kt @@ -0,0 +1,83 @@ +package network.bisq.mobile.client.market + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.client.service.Polling +import network.bisq.mobile.domain.data.BackgroundDispatcher +import network.bisq.mobile.domain.data.model.market_price.MarketPriceItem +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.utils.Logging + +class ClientMarketPriceServiceFacade( + private val apiGateway: MarketPriceApiGateway +) : MarketPriceServiceFacade, Logging { + + // Properties + private val _marketPriceItem = MutableStateFlow(MarketPriceItem(Market.USD)) + override val marketPriceItem: StateFlow get() = _marketPriceItem + + // Misc + private val coroutineScope = CoroutineScope(BackgroundDispatcher) + private var job: Job? = null + private var polling = Polling(60000) { requestMarketPriceQuotes() } + private var selectedMarket: Market = Market.USD // todo use persisted or user default + private val quotes: HashMap = HashMap() + + // Life cycle + override fun activate() { + requestMarketPriceQuotes() + polling.start() + } + + override fun deactivate() { + cancelJob() + polling.stop() + } + + // API + override fun selectMarket(marketListItem: MarketListItem) { + selectedMarket = marketListItem.market + _marketPriceItem.value = MarketPriceItem(marketListItem.market) + applyQuote() + } + + // Private + private fun requestMarketPriceQuotes() { + selectedMarket.let { + cancelJob() + job = coroutineScope.launch { + try { + val response: MarketPriceResponse = apiGateway.getQuotes() + quotes.putAll(response.quotes) + + applyQuote() + } catch (e: Exception) { + log.e("Error at API request", e) + } + } + } + } + + private fun applyQuote() { + val code = _marketPriceItem.value.market.quoteCurrencyCode + quotes[code]?.let { + _marketPriceItem.value.setQuote(it) + log.i { "applyQuote: code=$code; quote =$it" } + } + } + + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/MarketPriceApiGateway.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/MarketPriceApiGateway.kt new file mode 100644 index 00000000..8bc49086 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/market/MarketPriceApiGateway.kt @@ -0,0 +1,16 @@ +package network.bisq.mobile.client.market + +import kotlinx.serialization.Serializable +import network.bisq.mobile.client.service.ApiRequestService +import network.bisq.mobile.utils.Logging + +class MarketPriceApiGateway(private val apiRequestService: ApiRequestService) : Logging { + private val basePath = "market-price" + + suspend fun getQuotes(): MarketPriceResponse { + return apiRequestService.get("$basePath/quotes") + } +} + +@Serializable +class MarketPriceResponse(val quotes: Map) diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/ClientOfferbookServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/ClientOfferbookServiceFacade.kt new file mode 100644 index 00000000..ef7960d9 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/ClientOfferbookServiceFacade.kt @@ -0,0 +1,51 @@ +package network.bisq.mobile.client.offerbook + +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.client.offerbook.market.ClientMarketListItemService +import network.bisq.mobile.client.offerbook.market.ClientSelectedOfferbookMarketService +import network.bisq.mobile.client.offerbook.offer.ClientOfferbookListItemService +import network.bisq.mobile.client.offerbook.offer.OfferbookApiGateway +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.domain.data.model.offerbook.market.OfferbookMarket +import network.bisq.mobile.utils.Logging + +class ClientOfferbookServiceFacade( + apiGateway: OfferbookApiGateway, + private val marketPriceServiceFacade: MarketPriceServiceFacade +) : + OfferbookServiceFacade, Logging { + + // Properties + override val offerbookMarketItems: List get() = marketListItemService.marketListItems + override val offerListItems: StateFlow> get() = offerbookListItemService.offerListItems + override val selectedOfferbookMarket: StateFlow get() = selectedOfferbookMarketService.selectedOfferbookMarket + + // Misc + private val offerbookListItemService: ClientOfferbookListItemService = ClientOfferbookListItemService(apiGateway) + private val marketListItemService: ClientMarketListItemService = ClientMarketListItemService(apiGateway) + private val selectedOfferbookMarketService: ClientSelectedOfferbookMarketService = + ClientSelectedOfferbookMarketService(marketPriceServiceFacade) + + // Life cycle + override fun activate() { + marketListItemService.activate() + selectedOfferbookMarketService.activate() + offerbookListItemService.activate() + } + + override fun deactivate() { + marketListItemService.deactivate() + selectedOfferbookMarketService.deactivate() + offerbookListItemService.deactivate() + } + + // API + override fun selectMarket(marketListItem: MarketListItem) { + marketPriceServiceFacade.selectMarket(marketListItem) + selectedOfferbookMarketService.selectMarket(marketListItem) + offerbookListItemService.selectMarket(marketListItem) + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/ClientMarketListItemService.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/ClientMarketListItemService.kt new file mode 100644 index 00000000..6ab16bdd --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/ClientMarketListItemService.kt @@ -0,0 +1,102 @@ +package network.bisq.mobile.client.offerbook.market + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json +import network.bisq.mobile.client.offerbook.offer.OfferbookApiGateway +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.client.service.Polling +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.BackgroundDispatcher +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.utils.Logging + + +class ClientMarketListItemService(private val apiGateway: OfferbookApiGateway) : LifeCycleAware, + Logging { + + // Properties + private val _marketListItems: MutableList = mutableListOf() + val marketListItems: List get() = _marketListItems + + // Misc + private val coroutineScope = CoroutineScope(BackgroundDispatcher) + private var job: Job? = null + private var polling = Polling(1000) { updateNumOffers() } + private var marketListItemsRequested = false + + // Life cycle + override fun activate() { + // As markets are rather static we apply the default markets immediately. + // Markets would only change if we get new markets added to the market price server, + // which happens rarely. + val defaultMarkets = Json.decodeFromString>(DEFAULT_MARKETS) + fillMarketListItems(defaultMarkets) + // NumOffers are at default value (0) + + if (marketListItemsRequested) { + job = coroutineScope.launch { + try { + // TODO we might combine that api call to avoid 2 separate calls. + val markets = apiGateway.getMarkets() + fillMarketListItems(markets) + requestAndApplyNumOffers() + marketListItemsRequested = true + } catch (e: Exception) { + log.e("Error at API request", e) + } + } + } + polling.start() + } + + override fun deactivate() { + cancelJob() + polling.stop() + } + + // Private + private fun updateNumOffers() { + cancelJob() + job = coroutineScope.launch { requestAndApplyNumOffers() } + } + + private fun fillMarketListItems(markets: List) { + val list = markets.map { marketDto -> + val market = Market( + marketDto.baseCurrencyCode, + marketDto.quoteCurrencyCode, + marketDto.baseCurrencyName, + marketDto.quoteCurrencyName, + ) + + MarketListItem(market) + } + _marketListItems.addAll(list) + } + + private suspend fun requestAndApplyNumOffers() { + try { + val numOffersByMarketCode = apiGateway.getNumOffersByMarketCode() + marketListItems.map { marketListItem -> + val numOffers = + numOffersByMarketCode[marketListItem.market.quoteCurrencyCode] ?: 0 + marketListItem.setNumOffers(numOffers) + marketListItem + } + } catch (e: Exception) { + log.e("Error at API request", e) + } + } + + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/ClientSelectedOfferbookMarketService.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/ClientSelectedOfferbookMarketService.kt new file mode 100644 index 00000000..2bcc676e --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/ClientSelectedOfferbookMarketService.kt @@ -0,0 +1,67 @@ +package network.bisq.mobile.client.offerbook.market + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.BackgroundDispatcher +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.domain.data.model.offerbook.market.OfferbookMarket +import network.bisq.mobile.utils.Logging + +class ClientSelectedOfferbookMarketService( + private val marketPriceServiceFacade: MarketPriceServiceFacade +) : + LifeCycleAware, Logging { + + // Properties + private val _selectedOfferbookMarket = MutableStateFlow(OfferbookMarket.EMPTY) + val selectedOfferbookMarket: StateFlow get() = _selectedOfferbookMarket + + // Misc + private var selectedMarketListItem: MarketListItem = MarketListItem.USD + private val coroutineScope = CoroutineScope(BackgroundDispatcher) + private var job: Job? = null + + // Life cycle + override fun activate() { + job = observeMarketPrice() + } + + override fun deactivate() { + cancelJob() + } + + // API + fun selectMarket(marketListItem: MarketListItem) { + this.selectedMarketListItem = marketListItem + log.i { "selectMarket " + marketListItem } + _selectedOfferbookMarket.value = OfferbookMarket(marketListItem.market) + + cancelJob() + job = observeMarketPrice() + } + + + private fun observeMarketPrice(): Job { + return coroutineScope.launch { + marketPriceServiceFacade.marketPriceItem.collectLatest { marketPriceItem -> + _selectedOfferbookMarket.value.setFormattedPrice(marketPriceItem.formattedPrice.value) + } + } + } + + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/DefaultMarkets.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/DefaultMarkets.kt new file mode 100644 index 00000000..960ca2a3 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/market/DefaultMarkets.kt @@ -0,0 +1,39 @@ +package network.bisq.mobile.client.offerbook.market +val DEFAULT_MARKETS = """ + [ + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"USD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"US Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"EUR","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Euro"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"GBP","baseCurrencyName":"Bitcoin","quoteCurrencyName":"British Pound"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"CAD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Canadian Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"AUD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Australian Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"RUB","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Russian Ruble"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"CNY","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Chinese Yuan"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"INR","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Indian Rupee"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"NGN","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Nigerian Naira"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"BHD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Bahraini Dinar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"BDT","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Bangladeshi Taka"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"BMD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Bermudan Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"BRL","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Brazilian Real"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"CLP","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Chilean Peso"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"CZK","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Czech Koruna"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"DKK","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Danish Krone"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"GEL","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Georgian Lari"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"HKD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Hong Kong Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"HUF","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Hungarian Forint"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"IDR","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Indonesian Rupiah"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"ILS","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Israeli New Shekel"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"JPY","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Japanese Yen"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"KWD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Kuwaiti Dinar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"MYR","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Malaysian Ringgit"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"MXN","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Mexican Peso"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"MMK","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Myanmar Kyat"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"TWD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"New Taiwan Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"NZD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"New Zealand Dollar"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"NOK","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Norwegian Krone"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"PKR","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Pakistani Rupee"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"PHP","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Philippine Peso"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"PLN","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Polish Zloty"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"SAR","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Saudi Riyal"}, + {"baseCurrencyCode":"BTC","quoteCurrencyCode":"SGD","baseCurrencyName":"Bitcoin","quoteCurrencyName":"Singapore Dollar"} + ] + """.trimIndent() \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/offer/ClientOfferbookListItemService.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/offer/ClientOfferbookListItemService.kt new file mode 100644 index 00000000..290425f2 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/offer/ClientOfferbookListItemService.kt @@ -0,0 +1,71 @@ +package network.bisq.mobile.client.offerbook.offer + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import network.bisq.mobile.client.service.Polling +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.BackgroundDispatcher +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.utils.Logging + + +class ClientOfferbookListItemService(private val apiGateway: OfferbookApiGateway) : + LifeCycleAware, Logging { + + + // Properties + private val _offerListItems = MutableStateFlow>(emptyList()) + val offerListItems: StateFlow> get() = _offerListItems + + // Misc + private var job: Job? = null + private var polling = Polling(1000) { updateOffers() } + private var selectedMarket: MarketListItem? = null + private val coroutineScope = CoroutineScope(BackgroundDispatcher) + + // Life cycle + override fun activate() { + polling.start() + } + + override fun deactivate() { + cancelJob() + polling.stop() + } + + // API + fun selectMarket(marketListItem: MarketListItem) { + selectedMarket = marketListItem + updateOffers() + } + + private fun updateOffers() { + if (selectedMarket != null) { + cancelJob() + job = coroutineScope.launch { + try { + if (selectedMarket != null) { + _offerListItems.value = + apiGateway.getOffers(selectedMarket!!.market.quoteCurrencyCode) + } + } catch (e: Exception) { + log.e("Error at getOffers API request", e) + } + } + } + } + + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/offer/OfferbookApiGateway.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/offer/OfferbookApiGateway.kt new file mode 100644 index 00000000..442522bc --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/offerbook/offer/OfferbookApiGateway.kt @@ -0,0 +1,23 @@ +package network.bisq.mobile.client.offerbook.offer + +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.client.service.ApiRequestService +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem +import network.bisq.mobile.utils.Logging + +class OfferbookApiGateway(private val apiRequestService: ApiRequestService) : Logging { + private val basePath = "offerbook" + + suspend fun getMarkets(): List { + return apiRequestService.get("$basePath/markets") + } + + suspend fun getNumOffersByMarketCode(): Map { + return apiRequestService.get("$basePath/markets/offers/count") + } + + suspend fun getOffers(code: String): List { + return apiRequestService.get("$basePath/markets/$code/offers") + } +} + diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/common/currency/Market.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/common/currency/Market.kt new file mode 100644 index 00000000..2e174df6 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/common/currency/Market.kt @@ -0,0 +1,43 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ +package network.bisq.mobile.client.replicated_model.common.currency + +import kotlinx.serialization.Serializable + +@Serializable +class Market( + val baseCurrencyCode: String, + val quoteCurrencyCode: String, + val baseCurrencyName: String, + val quoteCurrencyName: String, +) { + companion object { + val EMPTY: Market = Market("", "", "", "") + val USD: Market = Market("BTC", "USD", "Bitcoin", "US Dollar") + private const val QUOTE_SEPARATOR = "/" + } + + val marketCodes: String + get() = baseCurrencyCode + QUOTE_SEPARATOR + quoteCurrencyCode + + override fun toString(): String { + return "Market(baseCurrencyCode='$baseCurrencyCode', " + + "quoteCurrencyCode='$quoteCurrencyCode', " + + "baseCurrencyName='$baseCurrencyName', " + + "quoteCurrencyName='$quoteCurrencyName'" + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/offer/Direction.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/offer/Direction.kt new file mode 100644 index 00000000..68af67cc --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/offer/Direction.kt @@ -0,0 +1,32 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ +package network.bisq.mobile.client.replicated_model.offer + +enum class Direction { + BUY, + SELL; + + val isBuy: Boolean + get() = this == BUY + + val isSell: Boolean + get() = this == SELL + + fun mirror(): Direction { + return if (isBuy) SELL else BUY + } +} diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/user/reputation/ReputationScore.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/user/reputation/ReputationScore.kt new file mode 100644 index 00000000..6100b35a --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/replicated_model/user/reputation/ReputationScore.kt @@ -0,0 +1,36 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ +package network.bisq.mobile.client.replicated_model.user.reputation + +import kotlinx.serialization.Serializable + +@Serializable +class ReputationScore( + val totalScore: Long, + val fiveSystemScore: Double, + val ranking: Int +) { + + companion object { + val NONE: ReputationScore = ReputationScore(0, 0.0, Int.MAX_VALUE) + } + + override fun toString(): String { + return "ReputationScore(totalScore=$totalScore, fiveSystemScore=$fiveSystemScore, ranking=$ranking)" + } +} + diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/ApiRequestService.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/ApiRequestService.kt index 62278dfb..68e4e51b 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/ApiRequestService.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/ApiRequestService.kt @@ -1,22 +1,33 @@ package network.bisq.mobile.client.service -import co.touchlab.kermit.Logger import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.get +import io.ktor.client.request.parameter import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.http.contentType +import network.bisq.mobile.utils.Logging -class ApiRequestService(val httpClient: HttpClient, host: String) { +class ApiRequestService(val httpClient: HttpClient, host: String): Logging { private var baseUrl = "http://$host:8082/api/v1/" + init{ + log.i { "API base URL = $baseUrl" } + } + fun endpoint(path: String) = baseUrl + path suspend inline fun get(path: String): T { return httpClient.get(endpoint(path)).body() } + suspend inline fun get(path: String, paramName: String, paramValue: String): T { + return httpClient.get(endpoint(path)) { + parameter(paramName, paramValue) + }.body() + } + suspend inline fun post(path: String, requestBody: Any): T { return httpClient.post(endpoint(path)) { contentType(io.ktor.http.ContentType.Application.Json) diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/Polling.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/Polling.kt new file mode 100644 index 00000000..c14a0ec9 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/service/Polling.kt @@ -0,0 +1,46 @@ +package network.bisq.mobile.client.service + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import network.bisq.mobile.domain.data.BackgroundDispatcher +import network.bisq.mobile.utils.Logging + +class Polling(private val intervalMillis: Long, private val task: () -> Unit) : Logging { + private var job: Job? = null + private var isRunning = false + private val coroutineScope = CoroutineScope(BackgroundDispatcher) + + fun start() { + if (!isRunning) { + isRunning = true + job = coroutineScope.launch { + while (isRunning) { + task() + delay(intervalMillis) + } + } + } + } + + fun stop() { + isRunning = false + cancelJob() + } + + fun restart() { + stop() + start() + } + + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt index 4220f3f3..3c04d1cf 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/ClientUserProfileServiceFacade.kt @@ -5,7 +5,7 @@ import kotlinx.datetime.Clock import network.bisq.mobile.client.replicated_model.user.identity.PreparedData import network.bisq.mobile.client.replicated_model.user.profile.UserProfile import network.bisq.mobile.client.user_profile.UserProfileResponse -import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.utils.Logging import kotlin.math.max import kotlin.math.min @@ -14,8 +14,10 @@ import kotlin.random.Random class ClientUserProfileServiceFacade(private val apiGateway: UserProfileApiGateway) : UserProfileServiceFacade, Logging { + // Misc private var preparedData: PreparedData? = null + // API override suspend fun hasUserProfile(): Boolean { return getUserIdentityIds().isNotEmpty() } @@ -66,6 +68,7 @@ class ClientUserProfileServiceFacade(private val apiGateway: UserProfileApiGatew } } + // Private private suspend fun getSelectedUserProfile(): UserProfile { return apiGateway.getSelectedUserProfile() } diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt index 8deeacad..d6e72400 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/client/user_profile/UserProfileApiGateway.kt @@ -1,6 +1,5 @@ package network.bisq.mobile.domain.client.main.user_profile -import co.touchlab.kermit.Logger import network.bisq.mobile.client.replicated_model.user.identity.PreparedData import network.bisq.mobile.client.replicated_model.user.profile.UserProfile import network.bisq.mobile.client.service.ApiRequestService @@ -18,7 +17,7 @@ class UserProfileApiGateway( suspend fun createAndPublishNewUserProfile( nickName: String, preparedData: PreparedData - ): UserProfileResponse { + ): UserProfileResponse { val createUserIdentityRequest = CreateUserIdentityRequest( nickName, "", diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/LifeCycleAware.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/LifeCycleAware.kt new file mode 100644 index 00000000..7e25f296 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/LifeCycleAware.kt @@ -0,0 +1,7 @@ +package network.bisq.mobile.domain + +interface LifeCycleAware { + fun activate() + + fun deactivate() +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/Currencies.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/Currencies.kt deleted file mode 100644 index b5ff1b74..00000000 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/Currencies.kt +++ /dev/null @@ -1,18 +0,0 @@ -package network.bisq.mobile.domain.data.model - -data class FiatCurrency( - val flagImage: String, - val name: String, - val code: String, - val offerCount: Number -) - -class Currencies(val currencies: List = listOf()): BaseModel() - -interface CurrenciesFactory { - fun createCurrencies(): Currencies -} - -class DefaultCurrenciesFactory : CurrenciesFactory { - override fun createCurrencies() = Currencies() -} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/market_price/MarketPriceItem.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/market_price/MarketPriceItem.kt new file mode 100644 index 00000000..c6a08590 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/market_price/MarketPriceItem.kt @@ -0,0 +1,27 @@ +package network.bisq.mobile.domain.data.model.market_price + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.domain.data.model.BaseModel + +/** + * Provides market price data + */ +data class MarketPriceItem(val market: Market) : BaseModel() { + private val _quote = MutableStateFlow(0L) + val quote: StateFlow get() = _quote + fun setQuote(value: Long) { + _quote.value = value + } + + private val _formattedPrice = MutableStateFlow("") + val formattedPrice: StateFlow get() = _formattedPrice + fun setFormattedPrice(value: String) { + _formattedPrice.value = value + } + + companion object { + val EMPTY: MarketPriceItem = MarketPriceItem(Market.EMPTY) + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/OfferListItem.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/OfferListItem.kt new file mode 100644 index 00000000..3eb2a68f --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/OfferListItem.kt @@ -0,0 +1,48 @@ +package network.bisq.mobile.domain.data.model.offerbook + +import kotlinx.serialization.Serializable +import network.bisq.mobile.client.replicated_model.offer.Direction +import network.bisq.mobile.client.replicated_model.user.reputation.ReputationScore +import network.bisq.mobile.domain.data.model.BaseModel + +/** + * For displaying offer data in the offerbook list + */ +@Serializable +data class OfferListItem( + val messageId: String, + val offerId: String, + val isMyMessage: Boolean, + val direction: Direction, + val offerTitle: String, + val date: Long, + val formattedDate: String, + val nym: String, + val userName: String, + val reputationScore: ReputationScore, + val formattedQuoteAmount: String, + val formattedPrice: String, + val quoteSidePaymentMethods: List, + val baseSidePaymentMethods: List, + val supportedLanguageCodes: String +) : BaseModel() { + override fun toString(): String { + return "OfferItem(\n" + + "MessageId ID='${messageId}'\n" + + "Offer ID='${offerId}'\n" + + "offerTitle='${offerTitle}'\n" + + "isMyMessage='${isMyMessage}'\n" + + "direction='${direction}'\n" + + "date='$date'\n" + + "formattedDate='$formattedDate'\n" + + "nym='$nym'\n" + + "userName='$userName'\n" + + "reputationScore=$reputationScore\n" + + "formattedQuoteAmount='$formattedQuoteAmount'\n" + + "formattedPrice='$formattedPrice'\n" + + "quoteSidePaymentMethods=$quoteSidePaymentMethods\n" + + "baseSidePaymentMethods=$baseSidePaymentMethods\n" + + "supportedLanguageCodes='$supportedLanguageCodes'\n" + + ")" + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/market/MarketListItem.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/market/MarketListItem.kt new file mode 100644 index 00000000..f5ce3e38 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/market/MarketListItem.kt @@ -0,0 +1,45 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ +package network.bisq.mobile.domain.data.model.offerbook.market + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.serialization.Serializable +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.domain.data.model.BaseModel + +/** + * Provides data for offerbook market list items + */ +@Serializable +class MarketListItem(val market: Market) : BaseModel() { + private val _numOffers = MutableStateFlow(0) + val numOffers: StateFlow get() = _numOffers + fun setNumOffers(value: Int) { + _numOffers.value = value + } + + override fun toString(): String { + return "MarketListItem(market=$market, " + + "_numOffers=$_numOffers" + } + + companion object { + val EMPTY: MarketListItem = MarketListItem(Market.EMPTY) + val USD: MarketListItem = MarketListItem(Market.USD) + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/market/OfferbookMarket.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/market/OfferbookMarket.kt new file mode 100644 index 00000000..35049692 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/model/offerbook/market/OfferbookMarket.kt @@ -0,0 +1,32 @@ +package network.bisq.mobile.domain.data.model.offerbook.market + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.serialization.Serializable +import network.bisq.mobile.client.replicated_model.common.currency.Market +import network.bisq.mobile.domain.data.model.BaseModel + +/** + * Provides data for the offerbook header showing the selected market data + */ +@Serializable +data class OfferbookMarket( + val market: Market +) : BaseModel() { + private val _formattedPrice = MutableStateFlow("") + val formattedPrice: StateFlow get() = _formattedPrice + fun setFormattedPrice(value: String) { + _formattedPrice.value = value + } + + override fun toString(): String { + return "OfferbookMarket(\n" + + "market='$market'\n" + + "formattedPrice='${formattedPrice.value}'\n" + + ")" + } + + companion object { + val EMPTY: OfferbookMarket = OfferbookMarket(Market.EMPTY) + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/CurrenciesRepository.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/CurrenciesRepository.kt deleted file mode 100644 index fd699350..00000000 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/CurrenciesRepository.kt +++ /dev/null @@ -1,52 +0,0 @@ -package network.bisq.mobile.domain.data.repository - -import kotlinx.coroutines.runBlocking -import network.bisq.mobile.domain.data.model.Currencies -import network.bisq.mobile.domain.data.model.FiatCurrency - -// TODO: -// androidNode will populate List from bisq2 libs -// xClients will populate List via API -open class CurrenciesRepository : SingleObjectRepository() { - init { - runBlocking { - val currencies = Currencies( - currencies = listOf( - FiatCurrency( - flagImage = "currency_aed.png", - name = "United Arab Emirates Dirham", - code = "aed", - offerCount = 9 - ), - FiatCurrency(flagImage = "currency_ars.png", name = "Argentine Peso", code = "ars", offerCount = 0), - FiatCurrency( - flagImage = "currency_aud.png", - name = "Australian Dollar", - code = "aud", - offerCount = 12 - ), - FiatCurrency(flagImage = "currency_eur.png", name = "Euro", code = "eur", offerCount = 66), - FiatCurrency( - flagImage = "currency_gbp.png", - name = "British Pound Sterling", - code = "gbp", - offerCount = 3 - ), - - FiatCurrency(flagImage = "currency_jpy.png", name = "Japanese Yen", code = "jpy", offerCount = 2), - - FiatCurrency(flagImage = "currency_qar.png", name = "Qatari Rial", code = "qar", offerCount = 4), - FiatCurrency(flagImage = "currency_sek.png", name = "Swedish Krona", code = "sek", offerCount = 18), - FiatCurrency( - flagImage = "currency_sgd.png", - name = "Singapore Dollar", - code = "sgd", - offerCount = 16 - ), - FiatCurrency(flagImage = "currency_usd.png", name = "US Dollar", code = "usd", offerCount = 62), - ) - ) - create(currencies) - } - } -} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt index a2cc2f3d..55533e20 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/data/repository/Repositories.kt @@ -3,7 +3,7 @@ package network.bisq.mobile.domain.data.repository import kotlinx.coroutines.runBlocking import network.bisq.mobile.domain.data.model.* -// this way of definingsupports both platforms +// this way of defining supports both platforms // add your repositories here and then in your DI module call this classes for instanciation open class GreetingRepository: SingleObjectRepository() open class BisqStatsRepository: SingleObjectRepository() diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt index cd0b9c0d..e8ed8699 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/di/DomainModule.kt @@ -10,5 +10,4 @@ val domainModule = module { single { BtcPriceRepository() } single { SettingsRepository() } single { MyTradesRepository() } - single { CurrenciesRepository() } } diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/bootstrap/ApplicationBootstrapFacade.kt similarity index 81% rename from bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt rename to bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/bootstrap/ApplicationBootstrapFacade.kt index 8eb2fff3..dcd31837 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/bootstrap/ApplicationBootstrapFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/bootstrap/ApplicationBootstrapFacade.kt @@ -2,10 +2,9 @@ package network.bisq.mobile.domain.data.repository.main.bootstrap import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.LifeCycleAware -abstract class ApplicationBootstrapFacade { - abstract fun initialize() - +abstract class ApplicationBootstrapFacade: LifeCycleAware { private val _state = MutableStateFlow("") val state: StateFlow = _state fun setState(value: String) { diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/market_price/MarketPriceServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/market_price/MarketPriceServiceFacade.kt new file mode 100644 index 00000000..99de5257 --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/market_price/MarketPriceServiceFacade.kt @@ -0,0 +1,11 @@ +package network.bisq.mobile.domain.service.market_price + +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.model.market_price.MarketPriceItem +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem + +interface MarketPriceServiceFacade : LifeCycleAware { + val marketPriceItem: StateFlow + fun selectMarket(marketListItem: MarketListItem) +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/offerbook/OfferbookServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/offerbook/OfferbookServiceFacade.kt new file mode 100644 index 00000000..c1426ede --- /dev/null +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/offerbook/OfferbookServiceFacade.kt @@ -0,0 +1,20 @@ +package network.bisq.mobile.domain.service.offerbook + +import kotlinx.coroutines.flow.StateFlow +import network.bisq.mobile.domain.LifeCycleAware +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +import network.bisq.mobile.domain.data.model.offerbook.market.OfferbookMarket + +interface OfferbookServiceFacade: LifeCycleAware { + val offerbookMarketItems: List + val offerListItems: StateFlow> + val selectedOfferbookMarket: StateFlow + + fun selectMarket(marketListItem: MarketListItem) + + companion object { + val mainCurrencies: List = + listOf("USD", "EUR", "GBP", "CAD", "AUD", "RUB", "CNY", "INR", "NGN") + } +} \ No newline at end of file diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt similarity index 97% rename from bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt rename to bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt index 60011040..656276a9 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/user_profile/UserProfileServiceFacade.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/domain/service/user_profile/UserProfileServiceFacade.kt @@ -1,4 +1,4 @@ -package network.bisq.mobile.domain.user_profile +package network.bisq.mobile.domain.service.user_profile interface UserProfileServiceFacade { /** diff --git a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/utils/Logging.kt b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/utils/Logging.kt index 21141722..4669e1e8 100644 --- a/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/utils/Logging.kt +++ b/bisqapps/shared/domain/src/commonMain/kotlin/network/bisq/mobile/utils/Logging.kt @@ -13,6 +13,18 @@ interface Logging { fun getLogger(anyObj: Any): Logger { val tag = anyObj::class.simpleName + return doGetLogger(tag) +} + +fun getLogger(tag: String): Logger { + return getLogger(tag) +} + +fun getLogger(): Logger { + return doGetLogger(null) +} + +private fun doGetLogger(tag: String?): Logger { return if (tag != null) { loggerCache.getOrPut(tag) { Logger.withTag(tag) } } else { diff --git a/bisqapps/shared/presentation/build.gradle.kts b/bisqapps/shared/presentation/build.gradle.kts index 23fde293..c50a5056 100644 --- a/bisqapps/shared/presentation/build.gradle.kts +++ b/bisqapps/shared/presentation/build.gradle.kts @@ -95,7 +95,6 @@ kotlin { implementation(libs.lyricist) implementation(libs.coil.compose) - } val commonTest by getting { dependencies { diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/crypto/market_btc.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/crypto/market_btc.png new file mode 100644 index 00000000..62499bb8 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/crypto/market_btc.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_aed.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aed.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_aed.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aed.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_afn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_afn.png new file mode 100644 index 00000000..33367aa8 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_afn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_all.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_all.png new file mode 100644 index 00000000..0bbd843f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_all.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_amd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_amd.png new file mode 100644 index 00000000..dfa4a2cc Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_amd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aoa.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aoa.png new file mode 100644 index 00000000..3c6b3b76 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aoa.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_ars.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ars.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_ars.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ars.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_aud.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aud.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_aud.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_aud.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_awg.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_awg.png new file mode 100644 index 00000000..df6951b3 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_awg.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_azn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_azn.png new file mode 100644 index 00000000..1f0c13d7 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_azn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bam.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bam.png new file mode 100644 index 00000000..aa1645d5 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bam.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bbd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bbd.png new file mode 100644 index 00000000..db3a3e91 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bbd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bdt.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bdt.png new file mode 100644 index 00000000..49125a19 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bdt.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bgn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bgn.png new file mode 100644 index 00000000..0e2c5c57 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bgn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bhd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bhd.png new file mode 100644 index 00000000..e211d577 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bhd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bif.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bif.png new file mode 100644 index 00000000..cb99b92e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bif.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bmd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bmd.png new file mode 100644 index 00000000..85cca0b8 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bmd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bnd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bnd.png new file mode 100644 index 00000000..b37d1079 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bnd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bob.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bob.png new file mode 100644 index 00000000..caeeebd4 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bob.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_brl.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_brl.png new file mode 100644 index 00000000..1e2b8ca6 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_brl.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bsd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bsd.png new file mode 100644 index 00000000..a080c681 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bsd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_btn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_btn.png new file mode 100644 index 00000000..73dec97e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_btn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bwp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bwp.png new file mode 100644 index 00000000..21bfbb98 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bwp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_byn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_byn.png new file mode 100644 index 00000000..b0954f63 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_byn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bzd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bzd.png new file mode 100644 index 00000000..6b8ecfba Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_bzd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cad.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cad.png new file mode 100644 index 00000000..4e850433 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cad.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_chf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_chf.png new file mode 100644 index 00000000..989260bb Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_chf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_clp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_clp.png new file mode 100644 index 00000000..70ee2f3a Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_clp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cny.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cny.png new file mode 100644 index 00000000..c1cc283c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cny.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cop.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cop.png new file mode 100644 index 00000000..c8cf3c3f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cop.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_crc.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_crc.png new file mode 100644 index 00000000..1f57125e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_crc.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cup.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cup.png new file mode 100644 index 00000000..b8247222 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cup.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cve.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cve.png new file mode 100644 index 00000000..e5dde203 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_cve.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_czk.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_czk.png new file mode 100644 index 00000000..af032602 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_czk.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_djf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_djf.png new file mode 100644 index 00000000..7493f3e8 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_djf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dkk.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dkk.png new file mode 100644 index 00000000..621daa60 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dkk.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dop.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dop.png new file mode 100644 index 00000000..71c3707b Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dop.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dzd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dzd.png new file mode 100644 index 00000000..b9d7b3b1 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_dzd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_egp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_egp.png new file mode 100644 index 00000000..a232ceab Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_egp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ern.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ern.png new file mode 100644 index 00000000..cee5dcaf Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ern.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_etb.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_etb.png new file mode 100644 index 00000000..df7a96bd Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_etb.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_eur.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_eur.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_eur.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_eur.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_fjd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_fjd.png new file mode 100644 index 00000000..0b0357a2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_fjd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_fkp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_fkp.png new file mode 100644 index 00000000..26292bf5 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_fkp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_gbp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gbp.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_gbp.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gbp.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gel.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gel.png new file mode 100644 index 00000000..2c515eb9 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gel.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ghs.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ghs.png new file mode 100644 index 00000000..764ed36e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ghs.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gip.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gip.png new file mode 100644 index 00000000..6ec13395 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gip.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gmd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gmd.png new file mode 100644 index 00000000..fce2d520 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gmd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gnf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gnf.png new file mode 100644 index 00000000..f417edc7 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gnf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gtq.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gtq.png new file mode 100644 index 00000000..3762fc4f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gtq.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gyd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gyd.png new file mode 100644 index 00000000..cc2747f7 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_gyd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_hkd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_hkd.png new file mode 100644 index 00000000..1b25ed31 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_hkd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_hnl.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_hnl.png new file mode 100644 index 00000000..7878aeac Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_hnl.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_htg.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_htg.png new file mode 100644 index 00000000..0e1d575d Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_htg.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_huf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_huf.png new file mode 100644 index 00000000..82fa248b Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_huf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_idr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_idr.png new file mode 100644 index 00000000..3774ed22 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_idr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ils.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ils.png new file mode 100644 index 00000000..5680385d Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ils.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_inr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_inr.png new file mode 100644 index 00000000..4b62d3f0 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_inr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_iqd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_iqd.png new file mode 100644 index 00000000..e9777513 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_iqd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_irr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_irr.png new file mode 100644 index 00000000..91353ca8 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_irr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_isk.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_isk.png new file mode 100644 index 00000000..50e154f9 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_isk.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jmd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jmd.png new file mode 100644 index 00000000..26555707 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jmd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jod.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jod.png new file mode 100644 index 00000000..f57bc710 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jod.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_jpy.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jpy.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_jpy.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_jpy.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kes.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kes.png new file mode 100644 index 00000000..f3e8e856 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kes.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kgs.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kgs.png new file mode 100644 index 00000000..bfc26596 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kgs.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_khr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_khr.png new file mode 100644 index 00000000..71c62640 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_khr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kmf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kmf.png new file mode 100644 index 00000000..1520037a Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kmf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kpw.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kpw.png new file mode 100644 index 00000000..8040a291 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kpw.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_krw.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_krw.png new file mode 100644 index 00000000..97ee15f6 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_krw.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kwd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kwd.png new file mode 100644 index 00000000..89bfbb49 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kwd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kyd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kyd.png new file mode 100644 index 00000000..6e6ea2ea Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kyd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kzt.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kzt.png new file mode 100644 index 00000000..fe461c2f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_kzt.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lak.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lak.png new file mode 100644 index 00000000..fe24e3ca Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lak.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lbp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lbp.png new file mode 100644 index 00000000..32f329ce Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lbp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lkr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lkr.png new file mode 100644 index 00000000..e014d056 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lkr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lrd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lrd.png new file mode 100644 index 00000000..62cf5632 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lrd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lsl.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lsl.png new file mode 100644 index 00000000..8f351f7e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lsl.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lyd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lyd.png new file mode 100644 index 00000000..249c6834 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_lyd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mad.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mad.png new file mode 100644 index 00000000..db471e63 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mad.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mdl.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mdl.png new file mode 100644 index 00000000..fe68b7fa Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mdl.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mga.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mga.png new file mode 100644 index 00000000..4dbbf5b2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mga.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mmk.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mmk.png new file mode 100644 index 00000000..b6d9cdcb Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mmk.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mnt.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mnt.png new file mode 100644 index 00000000..ab3c6bac Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mnt.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mop.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mop.png new file mode 100644 index 00000000..277f836a Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mop.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mru.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mru.png new file mode 100644 index 00000000..715f8cfc Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mru.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mur.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mur.png new file mode 100644 index 00000000..089a108e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mur.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mvr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mvr.png new file mode 100644 index 00000000..67ab7e22 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mvr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mwk.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mwk.png new file mode 100644 index 00000000..dd8765c5 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mwk.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mxn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mxn.png new file mode 100644 index 00000000..14216d1c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mxn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_myr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_myr.png new file mode 100644 index 00000000..975fc88e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_myr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mzn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mzn.png new file mode 100644 index 00000000..b02c7da2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_mzn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nad.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nad.png new file mode 100644 index 00000000..081a2165 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nad.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ngn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ngn.png new file mode 100644 index 00000000..7a1e6b3d Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ngn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nio.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nio.png new file mode 100644 index 00000000..9cb7f7e6 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nio.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nok.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nok.png new file mode 100644 index 00000000..b8ee950f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nok.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_npr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_npr.png new file mode 100644 index 00000000..12ab74c6 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_npr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nzd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nzd.png new file mode 100644 index 00000000..c8fe91a6 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_nzd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_omr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_omr.png new file mode 100644 index 00000000..0e1f7a62 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_omr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pab.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pab.png new file mode 100644 index 00000000..dce10301 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pab.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pen.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pen.png new file mode 100644 index 00000000..45f3918a Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pen.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pgk.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pgk.png new file mode 100644 index 00000000..464d33f0 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pgk.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_php.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_php.png new file mode 100644 index 00000000..e1df0afd Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_php.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pkr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pkr.png new file mode 100644 index 00000000..ffe0c45a Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pkr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pln.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pln.png new file mode 100644 index 00000000..4326d71c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pln.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pyg.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pyg.png new file mode 100644 index 00000000..2063345e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_pyg.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_qar.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_qar.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_qar.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_qar.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ron.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ron.png new file mode 100644 index 00000000..fe63a50c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ron.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rsd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rsd.png new file mode 100644 index 00000000..81a51d28 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rsd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rub.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rub.png new file mode 100644 index 00000000..1b067076 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rub.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rwf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rwf.png new file mode 100644 index 00000000..6d28eb99 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_rwf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sar.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sar.png new file mode 100644 index 00000000..755c3782 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sar.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sbd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sbd.png new file mode 100644 index 00000000..e27b711b Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sbd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_scr.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_scr.png new file mode 100644 index 00000000..d413c372 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_scr.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sdg.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sdg.png new file mode 100644 index 00000000..5b91805c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sdg.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_sek.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sek.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_sek.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sek.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_sgd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sgd.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_sgd.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sgd.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sle.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sle.png new file mode 100644 index 00000000..89af45e1 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sle.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sos.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sos.png new file mode 100644 index 00000000..34ad457f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_sos.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_srd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_srd.png new file mode 100644 index 00000000..8359fea9 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_srd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ssp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ssp.png new file mode 100644 index 00000000..dc282ac2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ssp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_stn.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_stn.png new file mode 100644 index 00000000..aaa1b0c5 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_stn.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_svc.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_svc.png new file mode 100644 index 00000000..229250b0 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_svc.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_syp.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_syp.png new file mode 100644 index 00000000..b4814bfd Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_syp.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_szl.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_szl.png new file mode 100644 index 00000000..ad212a16 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_szl.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_thb.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_thb.png new file mode 100644 index 00000000..47810133 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_thb.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tjs.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tjs.png new file mode 100644 index 00000000..a2ffb072 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tjs.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tmt.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tmt.png new file mode 100644 index 00000000..7c262c90 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tmt.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tnd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tnd.png new file mode 100644 index 00000000..58b2441c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tnd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_top.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_top.png new file mode 100644 index 00000000..ed7bc6b2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_top.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_try.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_try.png new file mode 100644 index 00000000..365cd14f Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_try.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ttd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ttd.png new file mode 100644 index 00000000..a88b4fb5 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ttd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_twd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_twd.png new file mode 100644 index 00000000..64ce6ee5 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_twd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tzs.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tzs.png new file mode 100644 index 00000000..27ec3f49 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_tzs.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uah.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uah.png new file mode 100644 index 00000000..6a1bbc18 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uah.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ugx.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ugx.png new file mode 100644 index 00000000..69d81a03 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ugx.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_usd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_usd.png similarity index 100% rename from bisqapps/shared/presentation/src/commonMain/composeResources/drawable/currency_usd.png rename to bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_usd.png diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uyu.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uyu.png new file mode 100644 index 00000000..447c4fb2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uyu.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uzs.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uzs.png new file mode 100644 index 00000000..ae7130ad Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_uzs.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ves.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ves.png new file mode 100644 index 00000000..bd0f6b00 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_ves.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_vnd.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_vnd.png new file mode 100644 index 00000000..c7cb25b9 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_vnd.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_vuv.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_vuv.png new file mode 100644 index 00000000..4c0837c8 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_vuv.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_wst.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_wst.png new file mode 100644 index 00000000..d3b77742 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_wst.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_xaf.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_xaf.png new file mode 100644 index 00000000..203166eb Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_xaf.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_yer.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_yer.png new file mode 100644 index 00000000..1c3e288a Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_yer.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zar.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zar.png new file mode 100644 index 00000000..72d48718 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zar.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zmw.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zmw.png new file mode 100644 index 00000000..ee403694 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zmw.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zwl.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zwl.png new file mode 100644 index 00000000..114f94e9 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/markets/fiat/market_zwl.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/bitcoin/ln.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/bitcoin/ln.png new file mode 100644 index 00000000..e14ea108 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/bitcoin/ln.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/bitcoin/main_chain.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/bitcoin/main_chain.png new file mode 100644 index 00000000..5b63b7c9 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/bitcoin/main_chain.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/ach_transfer.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/ach_transfer.png new file mode 100644 index 00000000..c9e3102c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/ach_transfer.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/add_custom_green.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/add_custom_green.png new file mode 100644 index 00000000..87f367ed Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/add_custom_green.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/add_custom_grey.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/add_custom_grey.png new file mode 100644 index 00000000..62f9c5f2 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/add_custom_grey.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/amazon_gift_card.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/amazon_gift_card.png new file mode 100644 index 00000000..aa93c2f0 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/amazon_gift_card.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/bizum.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/bizum.png new file mode 100644 index 00000000..c969f781 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/bizum.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_app.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_app.png new file mode 100644 index 00000000..7509787c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_app.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_by_mail.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_by_mail.png new file mode 100644 index 00000000..c0ea2170 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_by_mail.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_deposit.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_deposit.png new file mode 100644 index 00000000..7dc102aa Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/cash_deposit.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_1.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_1.png new file mode 100644 index 00000000..5e084499 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_1.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_2.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_2.png new file mode 100644 index 00000000..e1d6684e Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_2.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_3.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_3.png new file mode 100644 index 00000000..3f339736 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_3.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_4.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_4.png new file mode 100644 index 00000000..ce5be2ba Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_4.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_5.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_5.png new file mode 100644 index 00000000..0b1fa6ab Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_5.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_6.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_6.png new file mode 100644 index 00000000..ea786e51 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/custom_payment_6.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/f2f.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/f2f.png new file mode 100644 index 00000000..d44e8072 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/f2f.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/faster_payments.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/faster_payments.png new file mode 100644 index 00000000..9d3936da Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/faster_payments.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/interac_etransfer.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/interac_etransfer.png new file mode 100644 index 00000000..5b840b83 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/interac_etransfer.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/national_bank.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/national_bank.png new file mode 100644 index 00000000..d26c7795 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/national_bank.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/pay_id.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/pay_id.png new file mode 100644 index 00000000..b8ae0eb7 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/pay_id.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/pix.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/pix.png new file mode 100644 index 00000000..136b7918 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/pix.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/revolut.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/revolut.png new file mode 100644 index 00000000..df9f5cf0 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/revolut.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/sepa.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/sepa.png new file mode 100644 index 00000000..f4181e4b Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/sepa.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/sepa_instant.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/sepa_instant.png new file mode 100644 index 00000000..72e6e7f3 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/sepa_instant.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/strike.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/strike.png new file mode 100644 index 00000000..99e68c4c Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/strike.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/swift.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/swift.png new file mode 100644 index 00000000..9b112ed1 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/swift.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/upi.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/upi.png new file mode 100644 index 00000000..a67afc18 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/upi.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/us_postal_money_order.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/us_postal_money_order.png new file mode 100644 index 00000000..753a6295 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/us_postal_money_order.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/wise.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/wise.png new file mode 100644 index 00000000..4a00abca Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/wise.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/zelle.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/zelle.png new file mode 100644 index 00000000..61c48f61 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/fiat/zelle.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_green.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_green.png new file mode 100644 index 00000000..93c3b360 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_green.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_grey.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_grey.png new file mode 100644 index 00000000..c2cc5c6b Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_grey.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_white.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_white.png new file mode 100644 index 00000000..067b2090 Binary files /dev/null and b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment/interchangeable_white.png differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_ach.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_ach.png deleted file mode 100644 index b06b74b7..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_ach.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_bitcoin_round.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_bitcoin_round.png deleted file mode 100644 index 613bb8c0..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_bitcoin_round.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_lightning_round.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_lightning_round.png deleted file mode 100644 index 008d98b2..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_lightning_round.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_strike.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_strike.png deleted file mode 100644 index 8421d1f0..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_strike.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_uspmo.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_uspmo.png deleted file mode 100644 index 4b38ee19..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_uspmo.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_venmo.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_venmo.png deleted file mode 100644 index 041a723a..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_venmo.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_wise.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_wise.png deleted file mode 100644 index ea11d1c5..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_wise.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_zelle.png b/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_zelle.png deleted file mode 100644 index f5f5ed03..00000000 Binary files a/bisqapps/shared/presentation/src/commonMain/composeResources/drawable/payment_zelle.png and /dev/null differ diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt new file mode 100644 index 00000000..43f82450 --- /dev/null +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/client/ClientMainPresenter.kt @@ -0,0 +1,25 @@ +package network.bisq.mobile.client + +import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade +import network.bisq.mobile.domain.service.market_price.MarketPriceServiceFacade +import network.bisq.mobile.domain.service.offerbook.OfferbookServiceFacade +import network.bisq.mobile.presentation.MainPresenter + +class ClientMainPresenter( + private val applicationBootstrapFacade: ApplicationBootstrapFacade, + private val offerbookServiceFacade: OfferbookServiceFacade, + private val marketPriceServiceFacade: MarketPriceServiceFacade +) : MainPresenter() { + + override fun onViewAttached() { + applicationBootstrapFacade.activate() + offerbookServiceFacade.activate() + marketPriceServiceFacade.activate() + } + + override fun onViewUnattaching() { + applicationBootstrapFacade.deactivate() + offerbookServiceFacade.deactivate() + marketPriceServiceFacade.deactivate() + } +} \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt index 7a7e184f..55cca874 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/BasePresenter.kt @@ -71,6 +71,7 @@ abstract class BasePresenter(private val rootPresenter: MainPresenter?): ViewPre @CallSuper override fun onDestroying() { // default impl + log.i { "onDestroying" } } @CallSuper diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/MainPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/MainPresenter.kt index 4d688158..7a166ceb 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/MainPresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/MainPresenter.kt @@ -5,16 +5,16 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import network.bisq.mobile.android.node.BuildNodeConfig import network.bisq.mobile.client.shared.BuildConfig -import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade import network.bisq.mobile.presentation.ui.AppPresenter /** * Main Presenter as an example of implementation for now. */ -open class MainPresenter(private val applicationBootstrapFacade: ApplicationBootstrapFacade) : BasePresenter(null), AppPresenter { +open class MainPresenter() : + BasePresenter(null), AppPresenter { lateinit var navController: NavHostController - private set + private set override fun setNavController(controller: NavHostController) { navController = controller @@ -24,7 +24,6 @@ open class MainPresenter(private val applicationBootstrapFacade: ApplicationBoot private val _isContentVisible = MutableStateFlow(false) override val isContentVisible: StateFlow = _isContentVisible - private var applicationServiceInited = false // passthrough example // private val _greetingText: StateFlow = stateFlowFromRepository( @@ -39,22 +38,9 @@ open class MainPresenter(private val applicationBootstrapFacade: ApplicationBoot log.i { "iOS Client Version: ${BuildConfig.IOS_APP_VERSION}" } log.i { "Android Client Version: ${BuildConfig.IOS_APP_VERSION}" } log.i { "Android Node Version: ${BuildNodeConfig.APP_VERSION}" } - // CoroutineScope(BackgroundDispatcher).launch { - // greetingRepository.create(Greeting()) - // } - } - - override fun onViewAttached() { - super.onViewAttached() - - if (!applicationServiceInited) { - initializeServices() - applicationServiceInited = true - } - } - - protected open fun initializeServices() { - applicationBootstrapFacade.initialize() + // CoroutineScope(BackgroundDispatcher).launch { + // greetingRepository.create(Greeting()) + // } } // Toggle action diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt index f6be9d34..63b3a8d9 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/di/PresentationModule.kt @@ -2,13 +2,12 @@ package network.bisq.mobile.presentation.di import androidx.navigation.NavController import androidx.navigation.NavHostController +import network.bisq.mobile.client.ClientMainPresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.AppPresenter import network.bisq.mobile.presentation.ui.uicases.GettingStartedPresenter import network.bisq.mobile.presentation.ui.uicases.IGettingStarted -import network.bisq.mobile.presentation.ui.uicases.offers.CurrencyListPresenter -import network.bisq.mobile.presentation.ui.uicases.offers.ICurrencyList -import network.bisq.mobile.presentation.ui.uicases.offers.IOffersList +import network.bisq.mobile.presentation.ui.uicases.offers.MarketListPresenter import network.bisq.mobile.presentation.ui.uicases.offers.OffersListPresenter import network.bisq.mobile.presentation.ui.uicases.startup.CreateProfilePresenter import network.bisq.mobile.presentation.ui.uicases.startup.IOnboardingPresenter @@ -26,10 +25,11 @@ val presentationModule = module { single(named("RootNavController")) { getKoin().getProperty("RootNavController") } single(named("TabNavController")) { getKoin().getProperty("TabNavController") } - single { MainPresenter(get()) } bind AppPresenter::class + single { ClientMainPresenter(get(), get(), get()) } bind AppPresenter::class single { SplashPresenter( + get(), get(), get() ) @@ -63,12 +63,12 @@ val presentationModule = module { ) } bind ITrustedNodeSetupPresenter::class - single { CurrencyListPresenter(get(), get()) } bind ICurrencyList::class + single { MarketListPresenter(get(), get()) } - single { OffersListPresenter(get()) } bind IOffersList::class + single { OffersListPresenter(get(), get()) } - single { - (navController: NavController, tabController: NavController) -> MyTradesPresenter( + single { (navController: NavController, tabController: NavController) -> + MyTradesPresenter( get(), tabController = tabController, myTradesRepository = get() diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/CurrencyProfileCard.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/CurrencyProfileCard.kt index 9334e7a2..f1750611 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/CurrencyProfileCard.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/CurrencyProfileCard.kt @@ -1,34 +1,34 @@ package network.bisq.mobile.presentation.ui.components -import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import bisqapps.shared.presentation.generated.resources.Res -import cafe.adriel.lyricist.LocalStrings -import coil3.compose.AsyncImage -import network.bisq.mobile.domain.data.model.FiatCurrency +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.DynamicImage import network.bisq.mobile.presentation.ui.theme.BisqTheme -import org.jetbrains.compose.resources.DrawableResource -import org.jetbrains.compose.resources.ExperimentalResourceApi -import org.jetbrains.compose.resources.painterResource - -@OptIn(ExperimentalResourceApi::class) @Composable fun CurrencyProfileCard( - currency: FiatCurrency, - onClick: (FiatCurrency) -> Unit) { - - val strings = LocalStrings.current + item: MarketListItem, + onClick: () -> Unit +) { val interactionSource = remember { MutableInteractionSource() } + val numOffers = item.numOffers.collectAsState().value Row( verticalAlignment = Alignment.CenterVertically, @@ -39,32 +39,38 @@ fun CurrencyProfileCard( .clickable( interactionSource = interactionSource, indication = null, - onClick = { - onClick(currency) - } + onClick = onClick ) - , - ) { + ) { Row( verticalAlignment = Alignment.CenterVertically, ) { - DynamicImage("drawable/${currency.flagImage}", contentDescription = null) + // If the image is not available we get an exception here and we cannot use try/catch + // Is DynamicImage needed? If so we can pass it as + DynamicImage( + "drawable/markets/fiat/market_${item.market.quoteCurrencyCode + .lowercase() + .replace("-", "_")}.png", + modifier = Modifier.size(36.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) Column { BisqText.baseRegular( - text = currency.name, + text = item.market.quoteCurrencyName, color = BisqTheme.colors.light1, ) Spacer(modifier = Modifier.height(0.dp)) BisqText.baseRegular( - text = currency.code, + text = item.market.quoteCurrencyCode, color = BisqTheme.colors.grey2, ) } } BisqText.smallRegular( - text = "${currency.offerCount.toString()} ${strings.common_offers}", + text = "$numOffers offers", color = BisqTheme.colors.primary, ) } -} \ No newline at end of file +} + diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/DynamicImage.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/DynamicImage.kt index 43f004bd..efbb24a8 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/DynamicImage.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/DynamicImage.kt @@ -1,32 +1,43 @@ package network.bisq.mobile.presentation.ui.components.atoms -import androidx.compose.foundation.layout.size -import androidx.compose.material3.Text import androidx.compose.runtime.Composable - import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp import bisqapps.shared.presentation.generated.resources.Res -import bisqapps.shared.presentation.generated.resources.bisq_logo -import bisqapps.shared.presentation.generated.resources.currency_aed import coil3.compose.AsyncImage +import network.bisq.mobile.utils.getLogger import org.jetbrains.compose.resources.ExperimentalResourceApi -import org.jetbrains.compose.resources.painterResource - -// The idea of this Composable is to load images at run time with a string path. -// TODO: In case the image doesn't exist, it should be handled gracefully @OptIn(ExperimentalResourceApi::class) @Composable -fun DynamicImage(path: String, contentDescription: String?, modifier: Modifier? = Modifier) { +fun DynamicImage( + path: String, + fallbackPath: String? = null, + contentDescription: String = "", + modifier: Modifier = Modifier, + onImageLoadError: (String) -> Unit = {} +) { + // If image is not found we get an exception. If used inside AsyncImage we cannot use try/catch + // and error let app crash + var model: String? = null + try { + model = Res.getUri(path) + } catch (e: Exception) { + if (fallbackPath != null) { + try { + model = Res.getUri(fallbackPath) + } catch (e: Exception) { + getLogger("DynamicImage").i { "Could not find resource $fallbackPath" } + } + } else { + getLogger("DynamicImage").i { "Could not find resource $path" } + } + } AsyncImage( - model = Res.getUri(path), - //model = Res.getUri("drawable/currency_usd.png"), - //fallback = painterResource(Res.drawable.currency_aed), - contentDescription = null, - modifier = Modifier.size(36.dp), + model = model, + contentDescription = contentDescription, + modifier = modifier, onError = { - println("Error") + onImageLoadError.invoke(path) } ) -} \ No newline at end of file +} diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/PaymentMethods.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/PaymentMethods.kt index dbe595ef..f966f1ee 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/PaymentMethods.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/PaymentMethods.kt @@ -1,6 +1,5 @@ package network.bisq.mobile.presentation.ui.components.atoms -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size @@ -8,45 +7,46 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import bisqapps.shared.presentation.generated.resources.* -import bisqapps.shared.presentation.generated.resources.Res -import org.jetbrains.compose.resources.painterResource +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem // TODO: Get params and render apt @Composable -fun PaymentMethods() { - Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) { - Row (horizontalArrangement = Arrangement.spacedBy(12.dp)){ - Image( - painterResource(Res.drawable.payment_ach), "", - modifier = Modifier.size(15.dp) - ) - Image( - painterResource(Res.drawable.payment_strike), "", - modifier = Modifier.size(15.dp) - ) - Image( - painterResource(Res.drawable.payment_ach), "", - modifier = Modifier.size(15.dp) - ) - Image( - painterResource(Res.drawable.payment_uspmo), "", - modifier = Modifier.size(15.dp) - ) +fun PaymentMethods(item: OfferListItem) { + val baseSidePaymentMethods = item.baseSidePaymentMethods + val quoteSidePaymentMethods = item.quoteSidePaymentMethods + var customMethodCounter = 1 + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { + quoteSidePaymentMethods.forEach { paymentMethod -> + DynamicImage( + path = "drawable/payment/fiat/${ + paymentMethod + .lowercase() + .replace("-", "_") + }.png", + fallbackPath = "drawable/payment/fiat/custom_payment_${customMethodCounter++}.png", + modifier = Modifier.size(15.dp), + ) + } } - Image( - painterResource( Res.drawable.icon_right_arrow), "", - modifier = Modifier.size(24.dp) + DynamicImage( + "drawable/payment/interchangeable_grey.png", + modifier = Modifier.size(12.dp) ) - Row (horizontalArrangement = Arrangement.spacedBy(12.dp)){ - Image( - painterResource(Res.drawable.payment_bitcoin_round), "", - modifier = Modifier.size(15.dp) - ) - Image( - painterResource(Res.drawable.payment_lightning_round), "", - modifier = Modifier.size(15.dp) - ) + Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { + baseSidePaymentMethods.forEach { paymentMethod -> + DynamicImage( + "drawable/payment/bitcoin/${ + paymentMethod + .lowercase() + .replace("-", "_") + }.png", + modifier = Modifier.size(15.dp) + ) + } } } } \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/ProfileRating.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/ProfileRating.kt index 90bd9eb1..2e9b70d2 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/ProfileRating.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/atoms/ProfileRating.kt @@ -13,11 +13,14 @@ import androidx.compose.ui.unit.dp import bisqapps.shared.presentation.generated.resources.Res import bisqapps.shared.presentation.generated.resources.icon_star import bisqapps.shared.presentation.generated.resources.img_bot_image +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem import org.jetbrains.compose.resources.painterResource // TODO: Get params and render apt @Composable -fun ProfileRating() { +fun ProfileRating(item: OfferListItem) { + val fiveSystemScore:Int = item.reputationScore.fiveSystemScore.toInt() + Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) { Image( painterResource(Res.drawable.img_bot_image), "", @@ -25,10 +28,10 @@ fun ProfileRating() { ) Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { BisqText.smallMedium( - text = "Satoshi Ninja" + text = item.userName ) LazyRow(horizontalArrangement = Arrangement.spacedBy(2.dp)) { - items(5) { + items(fiveSystemScore) { Image( painterResource(Res.drawable.icon_star), "", modifier = Modifier.size(10.dp) diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt index 94b6722d..057e72bc 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/ConfirmationDialog.kt @@ -11,7 +11,6 @@ import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.molecules.BisqDialog import network.bisq.mobile.presentation.ui.theme.BisqTheme -// TODO: Update default params with translation keys @Composable fun ConfirmationDialog( title: String = "", diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/StateToggle.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/DirectionToggle.kt similarity index 77% rename from bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/StateToggle.kt rename to bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/DirectionToggle.kt index 577d41cc..22485aea 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/StateToggle.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/DirectionToggle.kt @@ -1,86 +1,94 @@ -package network.bisq.mobile.presentation.ui.components.molecules - -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.tween -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import network.bisq.mobile.presentation.ui.components.atoms.BisqText -import network.bisq.mobile.presentation.ui.theme.BisqTheme - -@Composable -fun StateToggle( - states: List, - transitionX: Dp -) { - var selectedOption by remember { - mutableStateOf(states[0]) - } - - val slideOffset by animateDpAsState( - targetValue = if (selectedOption == states[0]) 0.dp else transitionX, - animationSpec = tween(durationMillis = 300) - ) - - Surface( - shape = RoundedCornerShape(6.dp), - modifier = Modifier.wrapContentSize() - ) { - Box( - modifier = Modifier - .background(BisqTheme.colors.dark5) - .padding(6.dp) - ) { - Box( - modifier = Modifier - .offset(x = slideOffset) - .background(BisqTheme.colors.primary, RoundedCornerShape(4.dp)) - ) { - - BisqText.baseMedium( - text = selectedOption, - color = BisqTheme.colors.light1, - modifier = Modifier - .padding(horizontal = 32.dp, vertical = 12.dp) - .alpha(0f), - ) - } - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - states.forEach { text -> - BisqText.baseMedium( - text = text, - color = BisqTheme.colors.light1, - modifier = Modifier - .padding(horizontal = 32.dp, vertical = 12.dp) - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null, - onClick = { - selectedOption = text - } - ) - ) - } - } - } - } -} \ No newline at end of file +package network.bisq.mobile.presentation.ui.components.molecules + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import network.bisq.mobile.client.replicated_model.offer.Direction +import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.theme.BisqTheme + +@Composable +fun DirectionToggle( + directions: List, + initialDirection: Direction, + transitionX: Dp, + onStateChange: (Direction) -> Unit +) { + var selectedDirection by remember { + mutableStateOf(initialDirection) + } + + val slideOffset by animateDpAsState( + targetValue = if (selectedDirection == directions[0]) 0.dp else transitionX, + animationSpec = tween(durationMillis = 300) + ) + + Surface( + shape = RoundedCornerShape(6.dp), + modifier = Modifier.wrapContentSize() + ) { + Box( + modifier = Modifier + .background(BisqTheme.colors.dark5) + .padding(6.dp) + ) { + Box( + modifier = Modifier + .offset(x = slideOffset) + .background(BisqTheme.colors.primary, RoundedCornerShape(4.dp)) + ) { + + BisqText.baseMedium( + text = toDisplayString(selectedDirection), + color = BisqTheme.colors.light1, + modifier = Modifier + .padding(horizontal = 32.dp, vertical = 12.dp) + .alpha(0f), + ) + } + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + directions.forEach { direction -> + BisqText.baseMedium( + text = toDisplayString(direction), + color = BisqTheme.colors.light1, + modifier = Modifier + .padding(horizontal = 32.dp, vertical = 12.dp) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = { + selectedDirection = direction + onStateChange.invoke(direction) + } + ) + ) + } + } + } + } +} + +fun toDisplayString(direction: Direction): String { + return if (direction.mirror().isBuy) "Buy from" else "Sell to" +} diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt index 036cfb47..df2ba7db 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/OfferCard.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp import bisqapps.shared.presentation.generated.resources.Res import bisqapps.shared.presentation.generated.resources.icon_chat_outlined +import network.bisq.mobile.domain.data.model.offerbook.OfferListItem import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.PaymentMethods import network.bisq.mobile.presentation.ui.components.atoms.ProfileRating @@ -27,13 +28,11 @@ import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.jetbrains.compose.resources.painterResource @Composable -fun OfferCard( - onClick: () -> Unit -) { +fun OfferCard(item: OfferListItem, onClick: () -> Unit) { Row( modifier = Modifier.clip(shape = RoundedCornerShape(8.dp)).padding(vertical = 5.dp), - ) { + ) { Row( modifier = Modifier.background(color = BisqTheme.colors.dark5).padding(12.dp).clickable( interactionSource = remember { MutableInteractionSource() }, @@ -43,36 +42,39 @@ fun OfferCard( verticalAlignment = Alignment.CenterVertically ) { Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { - ProfileRating() - PaymentMethods() + ProfileRating(item) + PaymentMethods(item) } Column( horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.SpaceBetween ) { - BisqText.baseBold( - text = "1.00%", - color = BisqTheme.colors.primary + BisqText.baseRegular( + // text = "\$50 - \$200", + text = item.formattedQuoteAmount, + color = BisqTheme.colors.light1 ) BisqText.smallMedium( - text = "\$52,000 / BTC", + // text = "\$52,000 / BTC", + text = item.formattedPrice, color = BisqTheme.colors.grey1 ) - BisqText.baseRegular( - text = "\$50 - \$200", - color = BisqTheme.colors.light1 - ) + } } - VerticalDivider(thickness = 2.dp, color = BisqTheme.colors.grey3, modifier = Modifier.height(98.dp)) + VerticalDivider( + thickness = 2.dp, + color = BisqTheme.colors.grey3, + modifier = Modifier.height(98.dp) + ) Column( verticalArrangement = Arrangement.Center, modifier = Modifier.background(color = BisqTheme.colors.dark4) .padding(horizontal = 10.dp, vertical = 41.dp) ) { Image( - painterResource( - Res.drawable.icon_chat_outlined), "", + painterResource(Res.drawable.icon_chat_outlined), + "", modifier = Modifier.size(16.dp), ) } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt index 8e40ca96..5ec0bf5a 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/components/molecules/TopBar.kt @@ -13,24 +13,28 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import network.bisq.mobile.presentation.ui.components.atoms.BisqText import network.bisq.mobile.presentation.ui.components.atoms.icons.BellIcon 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.components.atoms.BisqText import network.bisq.mobile.presentation.ui.theme.BisqTheme -import org.jetbrains.compose.resources.ExperimentalResourceApi -@OptIn(ExperimentalMaterial3Api::class, ExperimentalResourceApi::class) +@OptIn(ExperimentalMaterial3Api::class) @Composable -fun TopBar(title: String = "", isHome:Boolean = false) { +fun TopBar( + title: String = "", + isHome: Boolean = false, + navigationIcon: @Composable () -> Unit = {} +) { TopAppBar( modifier = Modifier.padding(horizontal = 16.dp).padding(end = 16.dp), + navigationIcon = navigationIcon, colors = TopAppBarDefaults.topAppBarColors( containerColor = BisqTheme.colors.backgroundColor, ), title = { if (isHome) { - BisqLogoSmall(modifier = Modifier.height(34.dp).width(100.dp),) + BisqLogoSmall(modifier = Modifier.height(34.dp).width(100.dp)) } else { BisqText.h4Medium( text = title, diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/CurrencyListPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/CurrencyListPresenter.kt deleted file mode 100644 index 6e2ddc79..00000000 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/CurrencyListPresenter.kt +++ /dev/null @@ -1,49 +0,0 @@ -package network.bisq.mobile.presentation.ui.uicases.offers - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch -import network.bisq.mobile.domain.data.BackgroundDispatcher -import network.bisq.mobile.domain.data.model.FiatCurrency -import network.bisq.mobile.domain.data.repository.CurrenciesRepository -import network.bisq.mobile.presentation.BasePresenter -import network.bisq.mobile.presentation.MainPresenter -import network.bisq.mobile.presentation.ui.navigation.Routes - -class CurrencyListPresenter( - mainPresenter: MainPresenter, - private val currenciesRepository: CurrenciesRepository, -) : BasePresenter(mainPresenter), ICurrencyList { - - private val _currencies = MutableStateFlow>(emptyList()) - override val currencies: StateFlow> = _currencies - - override fun onSelectedCurrency(currency: FiatCurrency) { - rootNavigator.navigate(Routes.OfferList.name) - } - - private fun refresh() { - CoroutineScope(BackgroundDispatcher).launch { - try { - delay(1000) // TODO: To simulate loading. Yet to be handled - val currencies = currenciesRepository.fetch() - _currencies.value = currencies?.currencies ?: emptyList() - } catch (e: Exception) { - // Handle errors - println("Error: ${e.message}") - } - } - } - - override fun onViewAttached() { - super.onViewAttached() - refresh() - } - - override fun onResume() { - super.onResume() - refresh() - } -} diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/MarketListPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/MarketListPresenter.kt new file mode 100644 index 00000000..85e12e85 --- /dev/null +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/MarketListPresenter.kt @@ -0,0 +1,38 @@ +package network.bisq.mobile.presentation.ui.uicases.offers + +import network.bisq.mobile.domain.data.model.offerbook.market.MarketListItem +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 MarketListPresenter( + mainPresenter: MainPresenter, + private val offerbookServiceFacade: OfferbookServiceFacade, + ) : BasePresenter(mainPresenter) { + + private var mainCurrencies = OfferbookServiceFacade.mainCurrencies + + var marketListItemWithNumOffers: List = offerbookServiceFacade.offerbookMarketItems + .sortedWith( + compareByDescending { it.numOffers.value } + .thenByDescending { mainCurrencies.contains(it.market.quoteCurrencyCode.lowercase()) } // [1] + .thenBy { item-> + if (!mainCurrencies.contains(item.market.quoteCurrencyCode.lowercase())) item.market.quoteCurrencyName + else null // Null values will naturally be sorted together + } + ) + // [1] thenBy doesn’t work as expected for boolean expressions because true and false are + // sorted alphabetically (false before true), thus we use thenByDescending + + fun onSelectMarket(marketListItem: MarketListItem) { + offerbookServiceFacade.selectMarket(marketListItem) + rootNavigator.navigate(Routes.OfferList.name) + } + + override fun onViewAttached() { + } + + override fun onViewUnattaching() { + } +} diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/CurrencyListScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/MarketListScreen.kt similarity index 66% rename from bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/CurrencyListScreen.kt rename to bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/MarketListScreen.kt index 28319410..b5203052 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/CurrencyListScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/MarketListScreen.kt @@ -1,34 +1,29 @@ package network.bisq.mobile.presentation.ui.uicases.offers -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items 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 kotlinx.coroutines.flow.StateFlow -import network.bisq.mobile.presentation.ui.components.CurrencyProfileCard import network.bisq.mobile.components.MaterialTextField -import network.bisq.mobile.domain.data.model.FiatCurrency -import network.bisq.mobile.presentation.ViewPresenter +import network.bisq.mobile.presentation.ui.components.CurrencyProfileCard import network.bisq.mobile.presentation.ui.components.atoms.icons.SortIcon import network.bisq.mobile.presentation.ui.components.layout.BisqStaticLayout import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import org.koin.compose.koinInject -interface ICurrencyList : ViewPresenter { - val currencies: StateFlow> - fun onSelectedCurrency(currency: FiatCurrency) -} - @Composable fun CurrencyListScreen() { val strings = LocalStrings.current - val presenter: ICurrencyList = koinInject() - val currencies: List = presenter.currencies.collectAsState().value + val presenter: MarketListPresenter = koinInject() RememberPresenterLifecycle(presenter) @@ -43,13 +38,13 @@ fun CurrencyListScreen() { } Spacer(modifier = Modifier.height(12.dp)) - LazyColumn() { - items(currencies) { currency -> + LazyColumn { + items(presenter.marketListItemWithNumOffers) { item -> CurrencyProfileCard( - currency, - onClick = { presenter.onSelectedCurrency(it) }) + item, + onClick = { presenter.onSelectMarket(item) } + ) } } - } } \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt index 53bd1c94..b15a988a 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListPresenter.kt @@ -1,14 +1,36 @@ 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.offerbook.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.ui.navigation.Routes open class OffersListPresenter( - mainPresenter: MainPresenter -) : BasePresenter(mainPresenter), IOffersList { + mainPresenter: MainPresenter, + private val offerbookServiceFacade: OfferbookServiceFacade, +) : BasePresenter(mainPresenter) { - override fun takeOffer() { - rootNavigator.navigate(Routes.OfferList.name) + val offerListItems: StateFlow> = offerbookServiceFacade.offerListItems + + private val _selectedDirection = MutableStateFlow(Direction.SELL) + val selectedDirection: StateFlow = _selectedDirection + + override fun onViewAttached() { + } + + override fun onViewUnattaching() { + } + + fun takeOffer() { + log.i { "take offer clicked " } + //todo show take offer screen + // rootNavigator.navigate(Routes.OfferList.name) + } + + fun onSelectDirection(direction: Direction) { + _selectedDirection.value = direction } } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListScreen.kt index 778825c8..f9fbd201 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/offers/OffersListScreen.kt @@ -9,36 +9,67 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.NavHostController import cafe.adriel.lyricist.LocalStrings -import network.bisq.mobile.presentation.ViewPresenter +import network.bisq.mobile.client.replicated_model.offer.Direction import network.bisq.mobile.presentation.ui.components.layout.BisqStaticScaffold -import network.bisq.mobile.presentation.ui.components.molecules.* +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 IOffersList : ViewPresenter { - fun takeOffer() -} +import org.koin.core.qualifier.named @Composable fun OffersListScreen() { - val presenter: ICurrencyList = koinInject() + val presenter: OffersListPresenter = koinInject() val strings = LocalStrings.current - val states = listOf( - strings.offers_list_buy_from, - strings.offers_list_sell_to + // Offers are mirrored to what user wants. E.g. I want to buy Bitcoin using a sell offer + val offerDirections: List = listOf( + Direction.SELL, + Direction.BUY ) + val openDialog = remember { mutableStateOf(false) } + val rootNavController: NavController + val navController: NavHostController = koinInject(named("RootNavController")) + + val offerListItems = presenter.offerListItems.collectAsState().value + val selectedDirection = presenter.selectedDirection.collectAsState().value + val filteredList = offerListItems.filter { it.direction == selectedDirection } + val sortedList = filteredList.sortedByDescending { it.date } RememberPresenterLifecycle(presenter) BisqStaticScaffold( topBar = { - TopBar(title = strings.common_offers) + TopBar( + title = strings.common_offers, + false, + navigationIcon = { + IconButton(onClick = { navController.popBackStack() }) { + Icon( + Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back", + tint = BisqTheme.colors.primary + ) + } + }, + ) }, ) { Box(modifier = Modifier.fillMaxSize()) { @@ -47,20 +78,24 @@ fun OffersListScreen() { modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { - StateToggle(states, 130.dp) + DirectionToggle( + offerDirections, + presenter.selectedDirection.value, + 130.dp + ) { direction -> + presenter.onSelectDirection(direction) + } Spacer(modifier = Modifier.height(32.dp)) + LazyColumn( modifier = Modifier.padding(10.dp), verticalArrangement = Arrangement.spacedBy(18.dp) ) { - items(3) { - OfferCard(onClick = { - // TODO: Do navigation here - }) + items(sortedList) { item -> + OfferCard(item, onClick = { presenter.takeOffer() }) } } - } } } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt index 5bfd1667..97501883 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfilePresenter.kt @@ -1,22 +1,23 @@ package network.bisq.mobile.presentation.ui.uicases.startup +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import network.bisq.mobile.domain.data.BackgroundDispatcher -import network.bisq.mobile.domain.user_profile.UserProfileServiceFacade +import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes - open class CreateProfilePresenter( mainPresenter: MainPresenter, private val userProfileService: UserProfileServiceFacade ) : BasePresenter(mainPresenter) { + // Properties private val _id = MutableStateFlow("") val id: StateFlow get() = _id private fun setId(value: String) { @@ -47,52 +48,73 @@ open class CreateProfilePresenter( _createAndPublishInProgress.value = value } + // Misc + private val coroutineScope = + CoroutineScope(Dispatchers.Main) // rootNavigator.navigate requires Dispatchers.Main + private var job: Job? = null + + // Lifecycle override fun onViewAttached() { - onGenerateKeyPair() + generateKeyPair() + } - // Currently we just always show the create profile page. - // We need to make the UI behaving to the intended use case. - // 1. After loading screen -> check if there is an existing user profile by - // calling `userProfileRepository.service.hasUserProfile()` - // 1a. If there is an existing user profile, do not show create user profile screen, - // but show user profile is some not yet defined way (right top corner in Desktop shows user profile). - // `userProfileRepository.service.applySelectedUserProfile()` fills the user profile data to - // userProfileRepository.model to be used in the UI. - // 1b. If there is no existing user profile, show create profile screen and call - // `onGenerateKeyPair()` when view is ready. + override fun onViewUnattaching() { + cancelJob() } + // UI handlers fun onGenerateKeyPair() { - // takes 200 -1000 ms - CoroutineScope(BackgroundDispatcher).launch { - setGenerateKeyPairInProgress(true) - log.i { "Show busy animation for generateKeyPair" } - userProfileService.generateKeyPair { id, nym -> - setId(id) - setNym(nym) - //todo show new profile image - } - setGenerateKeyPairInProgress(false) - log.i { "Hide busy animation for generateKeyPair" } - } + generateKeyPair() } fun onCreateAndPublishNewUserProfile() { if (nickName.value.isNotEmpty()) { - CoroutineScope(BackgroundDispatcher).launch { + // We would never call generateKeyPair while generateKeyPair is not + // completed, thus we can assign to same job reference + job = coroutineScope.launch { setCreateAndPublishInProgress(true) log.i { "Show busy animation for createAndPublishInProgress" } userProfileService.createAndPublishNewUserProfile(nickName.value) log.i { "Hide busy animation for createAndPublishInProgress" } setCreateAndPublishInProgress(false) - CoroutineScope(Dispatchers.Main).launch { - // todo stop busy animation in UI - rootNavigator.navigate(Routes.TrustedNodeSetup.name) { - popUpTo(Routes.CreateProfile.name) { inclusive = true } - } + // todo stop busy animation in UI + // Skip for now the TrustedNodeSetup until its fully implemented with persisting the api URL. + /* rootNavigator.navigate(Routes.TrustedNodeSetup.name) { + popUpTo(Routes.CreateProfile.name) { inclusive = true } + } */ + rootNavigator.navigate(Routes.TabContainer.name) { + popUpTo(Routes.CreateProfile.name) { inclusive = true } } } } } + + // Private + private fun generateKeyPair() { + // We would never call onCreateAndPublishNewUserProfile while generateKeyPair is not + // completed, thus we can assign to same job reference + cancelJob() + job = coroutineScope.launch { + setGenerateKeyPairInProgress(true) + log.i { "Show busy animation for generateKeyPair" } + // takes 200 -1000 ms + userProfileService.generateKeyPair { id, nym -> + setId(id) + setNym(nym) + //todo show new profile image + } + setGenerateKeyPairInProgress(false) + log.i { "Hide busy animation for generateKeyPair" } + } + } + + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt index 5346622e..86f4b3dc 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/CreateProfileScreen.kt @@ -16,14 +16,13 @@ import bisqapps.shared.presentation.generated.resources.img_bot_image 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.BisqTextField import network.bisq.mobile.presentation.ui.components.atoms.icons.BisqLogo +import network.bisq.mobile.presentation.ui.components.layout.BisqScrollScaffold +import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.jetbrains.compose.resources.painterResource import org.koin.compose.koinInject -import org.koin.core.qualifier.named -import network.bisq.mobile.presentation.ui.components.atoms.BisqTextField -import network.bisq.mobile.presentation.ui.components.layout.BisqScrollScaffold -import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/OnBoardingScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/OnBoardingScreen.kt index 2ae04fa9..949f694d 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/OnBoardingScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/OnBoardingScreen.kt @@ -4,28 +4,25 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.navigation.NavHostController import cafe.adriel.lyricist.LocalStrings import kotlinx.coroutines.CoroutineScope import network.bisq.mobile.presentation.ViewPresenter - -import network.bisq.mobile.presentation.ui.components.atoms.icons.BisqLogo 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.BisqLogo import network.bisq.mobile.presentation.ui.components.layout.BisqScrollScaffold import network.bisq.mobile.presentation.ui.components.organisms.BisqPagerView import network.bisq.mobile.presentation.ui.composeModels.PagerViewItem import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle -import network.bisq.mobile.presentation.ui.theme.* +import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.jetbrains.compose.resources.ExperimentalResourceApi import org.koin.compose.koinInject -import org.koin.core.parameter.parametersOf -import org.koin.core.qualifier.named -interface IOnboardingPresenter: ViewPresenter { +interface IOnboardingPresenter : ViewPresenter { val onBoardingData: List @@ -54,7 +51,7 @@ fun OnBoardingScreen() { BisqText.h1Light( text = strings.onboarding_bisq2_headline, color = BisqTheme.colors.grey1, - ) + ) Spacer(modifier = Modifier.height(56.dp)) BisqPagerView(pagerState, finalPages) Spacer(modifier = Modifier.height(56.dp)) @@ -63,7 +60,5 @@ fun OnBoardingScreen() { text = if (pagerState.currentPage == presenter.indexesToShow.lastIndex) strings.onboarding_button_create_profile else strings.buttons_next, onClick = { presenter.onNextButtonClick(coroutineScope, pagerState) } ) - } - } \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt index 9df7eb06..659af3d9 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/startup/SplashPresenter.kt @@ -1,48 +1,64 @@ package network.bisq.mobile.presentation.ui.uicases.startup +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import network.bisq.mobile.domain.data.BackgroundDispatcher import network.bisq.mobile.domain.data.repository.main.bootstrap.ApplicationBootstrapFacade +import network.bisq.mobile.domain.service.user_profile.UserProfileServiceFacade import network.bisq.mobile.presentation.BasePresenter import network.bisq.mobile.presentation.MainPresenter import network.bisq.mobile.presentation.ui.navigation.Routes - open class SplashPresenter( mainPresenter: MainPresenter, - applicationBootstrapFacade: ApplicationBootstrapFacade + private val applicationBootstrapFacade: ApplicationBootstrapFacade, + private val userProfileService: UserProfileServiceFacade ) : BasePresenter(mainPresenter) { - private val coroutineScope = CoroutineScope(Dispatchers.Main) val state: StateFlow = applicationBootstrapFacade.state val progress: StateFlow = applicationBootstrapFacade.progress + private var job: Job? = null + private val coroutineScope = CoroutineScope(BackgroundDispatcher) + override fun onViewAttached() { - coroutineScope.launch { + job = coroutineScope.launch { progress.collect { value -> when { value == 1.0f -> navigateToNextScreen() } } } - log.i { "Splash presenter attached" } } override fun onViewUnattaching() { - super.onViewUnattaching() - log.i { "Splash presenter unnattached" } + cancelJob() } private fun navigateToNextScreen() { - // TODO: Conditional nav - Will implement once we got persistant storage from nish to save flags - // If firstTimeApp launch, goto Onboarding[clientMode] (androidNode / xClient) - // If not, goto TabContainerScreen - // rootNavigator.navigate(Routes.Onboarding.name) { - rootNavigator.navigate(Routes.TabContainer.name) { - popUpTo(Routes.Splash.name) { inclusive = true } + CoroutineScope(Dispatchers.Main).launch { + if (userProfileService.hasUserProfile()) { + rootNavigator.navigate(Routes.TabContainer.name) { + popUpTo(Routes.Splash.name) { inclusive = true } + } + } else { + rootNavigator.navigate(Routes.CreateProfile.name) { + popUpTo(Routes.Splash.name) { inclusive = true } + } + } } } + private fun cancelJob() { + try { + job?.cancel() + job = null + } catch (e: CancellationException) { + log.e("Job cancel failed", e) + } + } } diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTrades.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTrades.kt new file mode 100644 index 00000000..c5898ff5 --- /dev/null +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTrades.kt @@ -0,0 +1,30 @@ + +package network.bisq.mobile.presentation.ui.uicases.trades + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.navigation.NavHostController +import network.bisq.mobile.presentation.ui.components.atoms.BisqText +import network.bisq.mobile.presentation.ui.theme.BisqTheme +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.koin.compose.koinInject +import org.koin.core.qualifier.named + +@OptIn(ExperimentalResourceApi::class) +@Composable +fun MyTrades() { + val rootNavController: NavHostController = koinInject(named("RootNavController")) + Box( + modifier = Modifier + .fillMaxSize(), + contentAlignment = Alignment.Center // Centers the content within the Box + ) { + BisqText.h2Regular( + text = "My Trades", + color = BisqTheme.colors.light1, + ) + } +} \ No newline at end of file diff --git a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt index ef2d6647..b5831eb4 100644 --- a/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt +++ b/bisqapps/shared/presentation/src/commonMain/kotlin/network/bisq/mobile/presentation/ui/uicases/trades/MyTradesScreen.kt @@ -1,7 +1,11 @@ package network.bisq.mobile.presentation.ui.uicases.trades import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.runtime.Composable @@ -19,7 +23,6 @@ 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.layout.BisqScrollLayout -import network.bisq.mobile.presentation.ui.components.molecules.OfferCard import network.bisq.mobile.presentation.ui.helpers.RememberPresenterLifecycle import network.bisq.mobile.presentation.ui.theme.BisqTheme import org.jetbrains.compose.resources.painterResource @@ -27,7 +30,7 @@ import org.koin.compose.koinInject import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named -interface IMyTrades: ViewPresenter { +interface IMyTrades : ViewPresenter { val myTrades: StateFlow> fun navigateToCurrencyList() @@ -38,7 +41,7 @@ fun MyTradesScreen() { val navController: NavHostController = koinInject(named("RootNavController")) val tabController: NavHostController = koinInject(named("TabNavController")) - val presenter: IMyTrades = koinInject { parametersOf(navController, tabController) } + val presenter: IMyTrades = koinInject { parametersOf(navController, tabController) } val myTrades: List = presenter.myTrades.collectAsState().value @@ -56,11 +59,11 @@ fun MyTradesScreen() { @Composable fun TradeList(presenter: IMyTrades, myTrades: List) { - LazyColumn(modifier = Modifier.padding(top= 48.dp)) { - items(myTrades) { offer -> - OfferCard( onClick = {} ) - } + LazyColumn(modifier = Modifier.padding(top = 48.dp)) { + items(myTrades) { offer -> + //OfferCard( onClick = {} ) } + } } @@ -71,7 +74,7 @@ fun NoTradesSection(presenter: IMyTrades) { modifier = Modifier.padding(vertical = 52.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(64.dp) - ){ + ) { Image( painterResource(Res.drawable.img_no_trades), "", modifier = Modifier.height(272.dp).width(350.dp)