Skip to content

Commit

Permalink
Add offerbook and marketprice domain (#78)
Browse files Browse the repository at this point in the history
* Add dependency to bisq-easy library

* Add markets images

* Add payment images

* Remove outdated payment images

* Apply offerbook and market price domain

* Add default markets

* Remove unused onCreate method

* Use field for coroutineScope
Add cancelJob method with exception handling

* Refactor: Move serviceFacade packages into new service package

* Refactor: Move view model classes into data/model

* Let view models extend BaseModel

* Add overload methods for passing a string or no argument (Default logger)

* Use logger instead of println

* Rename all image to use `_` instead of `-`

* Rename image path to use `_` instead of `-`

* Rename private method

* Refactor: Rename to match domain terms

* - fix android lint compilation errors on android node

---------

Co-authored-by: Rodrigo Varela <[email protected]>
  • Loading branch information
HenrikJannsen and rodvar authored Nov 27, 2024
1 parent b73abf6 commit b548046
Show file tree
Hide file tree
Showing 259 changed files with 2,081 additions and 536 deletions.
1 change: 1 addition & 0 deletions bisqapps/androidNode/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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<String>(), userDataDir), Logging {

@Getter
class Supplier {
class Provider {
@Setter
lateinit var applicationService: AndroidApplicationService
var stateSupplier: androidx.core.util.Supplier<Observable<State>> =
var state: Supplier<Observable<State>> =
Supplier { applicationService.state }
var securityServiceSupplier: androidx.core.util.Supplier<SecurityService> =
var securityService: Supplier<SecurityService> =
Supplier { applicationService.securityService }
var networkServiceSupplier: androidx.core.util.Supplier<NetworkService> =
var networkService: Supplier<NetworkService> =
Supplier { applicationService.networkService }
var identityServiceSupplier: androidx.core.util.Supplier<IdentityService> =
var identityService: Supplier<IdentityService> =
Supplier { applicationService.identityService }
var bondedRolesServiceSupplier: androidx.core.util.Supplier<BondedRolesService> =
var bondedRolesService: Supplier<BondedRolesService> =
Supplier { applicationService.bondedRolesService }
var accountServiceSupplier: androidx.core.util.Supplier<AccountService> =
var accountService: Supplier<AccountService> =
Supplier { applicationService.accountService }
var offerServiceSupplier: androidx.core.util.Supplier<OfferService> =
var offerService: Supplier<OfferService> =
Supplier { applicationService.offerService }
var contractServiceSupplier: androidx.core.util.Supplier<ContractService> =
var contractService: Supplier<ContractService> =
Supplier { applicationService.contractService }
var userServiceSupplier: androidx.core.util.Supplier<UserService> =
var userService: Supplier<UserService> =
Supplier { applicationService.userService }
var chatServiceSupplier: androidx.core.util.Supplier<ChatService> =
var chatService: Supplier<ChatService> =
Supplier { applicationService.chatService }
var settingsServiceSupplier: androidx.core.util.Supplier<SettingsService> =
var settingsService: Supplier<SettingsService> =
Supplier { applicationService.settingsService }
var supportServiceSupplier: androidx.core.util.Supplier<SupportService> =
var bisqEasyService: Supplier<BisqEasyService> =
Supplier { applicationService.bisqEasyService }
var supportService: Supplier<SupportService> =
Supplier { applicationService.supportService }
var systemNotificationServiceSupplier: androidx.core.util.Supplier<SystemNotificationService> =
var systemNotificationService: Supplier<SystemNotificationService> =
Supplier { applicationService.systemNotificationService }
var tradeServiceSupplier: androidx.core.util.Supplier<TradeService> =
var tradeService: Supplier<TradeService> =
Supplier { applicationService.tradeService }
var alertNotificationsServiceSupplier: androidx.core.util.Supplier<AlertNotificationsService> =
var alertNotificationsService: Supplier<AlertNotificationsService> =
Supplier { applicationService.alertNotificationsService }
var favouriteMarketsServiceSupplier: androidx.core.util.Supplier<FavouriteMarketsService> =
var favouriteMarketsService: Supplier<FavouriteMarketsService> =
Supplier { applicationService.favouriteMarketsService }
var dontShowAgainServiceSupplier: androidx.core.util.Supplier<DontShowAgainService> =
var dontShowAgainService: Supplier<DontShowAgainService> =
Supplier { applicationService.dontShowAgainService }
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -195,11 +216,11 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS
override fun initialize(): CompletableFuture<Boolean> {
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? ->
Expand Down Expand Up @@ -245,6 +266,10 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS
}
}

fun onStop() {
shutdown().join()
}

override fun shutdown(): CompletableFuture<Boolean> {
log.i("shutdown")
// We shut down services in opposite order as they are initialized
Expand Down Expand Up @@ -333,7 +358,6 @@ class AndroidApplicationService(androidMemoryReportService: AndroidMemoryReportS
}
}


private fun logError(throwable: Throwable): Boolean {
log.e("Exception at shutdown", throwable)
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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> { NodeGreetingRepository() }

single<AndroidMemoryReportService> {
AndroidMemoryReportService(androidContext())
}

single { AndroidApplicationService.Supplier() }
single { AndroidApplicationService.Provider() }

single<ApplicationBootstrapFacade> { NodeApplicationBootstrapFacade(get()) }

single<UserProfileServiceFacade> { NodeUserProfileServiceFacade(get()) }
single<MarketPriceServiceFacade> { NodeMarketPriceServiceFacade(get()) }

single<UserProfileServiceFacade> { NodeUserProfileServiceFacade(get()) }

single<OfferbookServiceFacade> { 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<MainPresenter> { NodeMainPresenter(get(), get(), get()) } bind AppPresenter::class
single<MainPresenter> { NodeMainPresenter(get(), get(), get(), get(), get()) } bind AppPresenter::class

single<IOnboardingPresenter> { OnBoardingNodePresenter(get()) } bind IOnboardingPresenter::class
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,61 @@
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<State> 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
State.INITIALIZE_WALLET -> {
}

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
}
}
Original file line number Diff line number Diff line change
@@ -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<MarketPriceItem> 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)
}
}
}
Loading

0 comments on commit b548046

Please sign in to comment.