Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add offerbook and marketprice domain #78

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading