Skip to content

Instantly share code, notes, and snippets.

@westonal
Created December 4, 2017 17:13
Show Gist options
  • Save westonal/31be9f60ba25ca802dcf23f5038b1a48 to your computer and use it in GitHub Desktop.
Save westonal/31be9f60ba25ca802dcf23f5038b1a48 to your computer and use it in GitHub Desktop.
package MVI
import electrum.Electrum
import io.reactivex.Observable
typealias WalletViewStateReducer = (WalletViewState) -> WalletViewState
class WalletModel(
val intent: Observable<WalletIntent>,
val electrum: Electrum
) {
val reducers: Observable<WalletViewStateReducer> =
intent.flatMap {
getStateReducer(it)
}
private fun getStateReducer(intent: WalletIntent): Observable<WalletViewStateReducer> =
when (intent) {
is WalletIntent.New -> {
Observable.just(getInitialStateReducer())
}
is WalletIntent.NewBlockHeight -> Observable.just({ state -> state.copy(blockHeight = intent.height) })
is WalletIntent.AddAddress -> getAddAddressStateReducer(intent)
is WalletIntent.RemoveAddress -> getRemoveAddressStateReducer(intent)
}
private fun getAddAddressStateReducer(intent: WalletIntent.AddAddress): Observable<WalletViewStateReducer> {
val value: WalletViewStateReducer = { it ->
upsertAddressReducer(it, AddressWalletViewState(intent.address, Electrum.Balance(intent.address)))
}
val maped: Observable<WalletViewStateReducer> =
electrum.balanceOf(intent.address)
.map { AddressWalletViewState(intent.address, it) }
.map { it -> { wallet: WalletViewState -> updateAddressReducer(wallet, it) } }
return Observable.just(value)
.concatWith(maped)
}
private fun getRemoveAddressStateReducer(intent: WalletIntent.RemoveAddress): Observable<WalletViewStateReducer> {
val value: WalletViewStateReducer = { it ->
removeAddressReducer(it, intent.address)
}
return Observable.just(value)
}
private fun upsertAddressReducer(wallet: WalletViewState, newAddressValue: AddressWalletViewState): WalletViewState {
val copy = wallet.addresses.toMutableList()
val idx = copy.indexOfFirst { (address) -> address == newAddressValue.address }
if (idx > -1)
copy[idx] = newAddressValue
else
copy += newAddressValue
return wallet.copy(addresses = copy)
}
private fun updateAddressReducer(wallet: WalletViewState, newAddressValue: AddressWalletViewState): WalletViewState {
val idx = wallet.addresses.indexOfFirst { (address) -> address == newAddressValue.address }
return if (idx > -1) {
val copy = wallet.addresses.toMutableList()
.also { it[idx] = newAddressValue }
wallet.copy(addresses = copy)
} else {
wallet
}
}
private fun removeAddressReducer(wallet: WalletViewState, newAddressValue: String): WalletViewState {
val copy = wallet.addresses.toMutableList()
copy.removeIf { (address) -> address == newAddressValue }
return wallet.copy(addresses = copy)
}
private fun getInitialStateReducer(): WalletViewStateReducer = { WalletViewState() }
val stream: Observable<WalletViewState> = reducers.scan(
WalletViewState(0, emptyList()),
{ oldState, reducer ->
reducer(oldState).also {
println("\toldState:\t$oldState")
println("\tnewState:\t$it")
}
}
)
}
fun walletDialog(intent: Observable<WalletIntent>, electrum: Electrum): Observable<WalletViewState> {
return WalletModel(intent, electrum).stream
}
data class AddressWalletViewState(
val address: String,
val balance: Electrum.Balance
)
data class WalletViewState(
val blockHeight: Int = 0,
val addresses: List<AddressWalletViewState> = emptyList()) {
val balanceConfirmed: Long = addresses.sumByDouble { it.balance.confirmed.toDouble() }.toLong()
val balanceUnconfirmed: Long = addresses.sumByDouble { it.balance.unconfirmed.toDouble() }.toLong()
}
sealed class WalletIntent {
class New : WalletIntent()
class NewBlockHeight(val height: Int) : WalletIntent()
class AddAddress(val address: String) : WalletIntent()
class RemoveAddress(val address: String) : WalletIntent()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment