demo: more wallet screen updates

This commit is contained in:
Oscar Mira 2023-04-20 18:54:11 +02:00
parent 8645d86d3e
commit ea15bf80c6
9 changed files with 159 additions and 29 deletions

View File

@ -41,9 +41,11 @@ class MoneroSdkClient(
loadBalancerRule = RoundRobinRule(),
httpClient = httpClient,
)
walletDataFileStorage.readData(publicAddress).use { input ->
val wallet = walletDataFileStorage.readData(publicAddress).use { input ->
provider.openWallet(network, client, input)
}
check(publicAddress == wallet.primaryAccountAddress) { "primary address mismatch" }
wallet
}
}
}

View File

@ -3,6 +3,7 @@ package im.molly.monero.demo.data
import im.molly.monero.demo.data.dao.WalletDao
import im.molly.monero.demo.data.entity.WalletEntity
import im.molly.monero.demo.data.entity.WalletRemoteNodeXRef
import im.molly.monero.demo.data.entity.asEntity
import im.molly.monero.demo.data.entity.asExternalModel
import im.molly.monero.demo.data.model.WalletConfig
import kotlinx.coroutines.flow.Flow
@ -11,12 +12,12 @@ import kotlinx.coroutines.flow.map
class WalletDataSource(
private val walletDao: WalletDao,
) {
fun getWalletIdList(): Flow<List<Long>> = walletDao.findAllIds()
fun readWalletIdList(): Flow<List<Long>> = walletDao.findAllIds()
fun loadWalletConfig(walletId: Long): Flow<WalletConfig> =
fun readWalletConfig(walletId: Long): Flow<WalletConfig> =
walletDao.findById(walletId).map { it.asExternalModel() }
suspend fun storeWalletConfig(
suspend fun createWalletConfig(
publicAddress: String,
name: String,
remoteNodeIds: List<Long>,
@ -36,4 +37,8 @@ class WalletDataSource(
walletDao.insertRemoteNodeXRefEntities(walletRemoteNodeXRef)
return walletId
}
suspend fun updateWalletConfig(walletConfig: WalletConfig) {
walletDao.update(walletConfig.asEntity())
}
}

View File

@ -1,6 +1,7 @@
package im.molly.monero.demo.data
import im.molly.monero.*
import im.molly.monero.demo.data.model.WalletConfig
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import java.util.concurrent.ConcurrentHashMap
@ -33,9 +34,9 @@ class WalletRepository(
}.await()
}
fun getWalletIdList() = walletDataSource.getWalletIdList()
fun getWalletIdList() = walletDataSource.readWalletIdList()
fun getWalletConfig(walletId: Long) = walletDataSource.loadWalletConfig(walletId)
fun getWalletConfig(walletId: Long) = walletDataSource.readWalletConfig(walletId)
fun getLedger(walletId: Long): Flow<Ledger> = flow {
emitAll(getWallet(walletId).ledger())
@ -47,11 +48,14 @@ class WalletRepository(
remoteNodeIds: List<Long>,
): Pair<Long, IWallet> {
val wallet = moneroSdkClient.createWallet(moneroNetwork)
val walletId = walletDataSource.storeWalletConfig(
val walletId = walletDataSource.createWalletConfig(
publicAddress = wallet.publicAddress,
name = name,
remoteNodeIds = remoteNodeIds,
)
return walletId to wallet
}
suspend fun updateWalletConfig(walletConfig: WalletConfig) =
walletDataSource.updateWalletConfig(walletConfig)
}

View File

@ -30,6 +30,9 @@ interface WalletDao {
@Insert(onConflict = OnConflictStrategy.ABORT)
suspend fun insertRemoteNodeXRefEntities(walletRemoteNodeXRefs: List<WalletRemoteNodeXRef>)
@Update
suspend fun update(wallet: WalletEntity)
@Delete
suspend fun delete(wallet: WalletEntity)
}

View File

@ -30,3 +30,9 @@ fun WalletEntity.asExternalModel() = WalletConfig(
name = name,
remoteNodes = setOf(),
)
fun WalletConfig.asEntity() = WalletEntity(
id = id,
publicAddress = publicAddress,
name = name
)

View File

@ -1,11 +1,8 @@
package im.molly.monero.demo.data.model
import im.molly.monero.MoneroNetwork
data class WalletConfig(
val id: Long,
val publicAddress: String,
val network: MoneroNetwork = MoneroNetwork.of(publicAddress),
val name: String,
val remoteNodes: Set<RemoteNode>,
)

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.lifecycle.LifecycleService
import androidx.lifecycle.lifecycleScope
import im.molly.monero.demo.AppModule
@ -13,6 +14,8 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.seconds
const val TAG = "SyncService"
class SyncService(
private val walletRepository: WalletRepository = AppModule.walletRepository,
) : LifecycleService() {
@ -24,11 +27,18 @@ class SyncService(
}
override fun onBind(intent: Intent): IBinder {
Log.d(TAG, "onBind: $intent")
super.onBind(intent)
return binder
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
return START_NOT_STICKY
}
override fun onCreate() {
Log.d(TAG, "onCreate")
super.onCreate()
lifecycleScope.launch {
@ -53,6 +63,11 @@ class SyncService(
}
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
super.onDestroy()
}
companion object {
fun start(context: Context) {
val intent = Intent(context, SyncService::class.java)

View File

@ -1,12 +1,22 @@
package im.molly.monero.demo.ui
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import im.molly.monero.Balance
import im.molly.monero.Ledger
import im.molly.monero.MoneroCurrency
import im.molly.monero.demo.R
import im.molly.monero.demo.data.model.WalletConfig
import im.molly.monero.demo.ui.component.Toolbar
import im.molly.monero.demo.ui.theme.AppIcons
@ -21,21 +31,59 @@ fun WalletRoute(
)
) {
val walletUiState: WalletUiState by viewModel.walletUiState.collectAsStateWithLifecycle()
WalletScreen(
walletUiState = walletUiState,
uiState = walletUiState,
onWalletConfigChange = { config -> viewModel.updateConfig(config) },
onBackClick = onBackClick,
modifier = modifier,
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun WalletScreen(
walletUiState: WalletUiState,
uiState: WalletUiState,
onWalletConfigChange: (WalletConfig) -> Unit,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
when (uiState) {
WalletUiState.Error -> WalletScreenError(onBackClick = onBackClick)
WalletUiState.Loading -> WalletScreenLoading(onBackClick = onBackClick)
is WalletUiState.Success -> WalletScreenPopulated(
walletConfig = uiState.config,
ledger = uiState.ledger,
onWalletConfigChange = onWalletConfigChange,
onBackClick = onBackClick,
modifier = modifier,
)
}
}
@Composable
private fun WalletScreenError(
onBackClick: () -> Unit,
) {
}
@Composable
private fun WalletScreenLoading(
onBackClick: () -> Unit,
) {
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun WalletScreenPopulated(
walletConfig: WalletConfig,
ledger: Ledger,
onWalletConfigChange: (WalletConfig) -> Unit,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
var showRenameDialog by remember { mutableStateOf(false) }
val amountValueString =
Scaffold(
topBar = {
Toolbar(
@ -48,11 +96,54 @@ private fun WalletScreen(
}
},
actions = {
WalletKebabMenu({}, {})
WalletKebabMenu(
onRenameClick = { showRenameDialog = true },
onDeleteClick = { },
)
}
)
}
) { padding ->
Column(
modifier = modifier
.fillMaxSize()
.padding(padding),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
style = MaterialTheme.typography.headlineLarge,
text = buildAnnotatedString {
append(MoneroCurrency.symbol + " ")
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(MoneroCurrency.format(ledger.balance.totalAmount))
}
}
)
Text(text = walletConfig.name, style = MaterialTheme.typography.headlineSmall)
}
if (showRenameDialog) {
var name by remember { mutableStateOf(walletConfig.name) }
AlertDialog(
onDismissRequest = { showRenameDialog = false },
title = { Text("Enter wallet name") },
text = {
OutlinedTextField(
value = name,
onValueChange = { name = it },
singleLine = true,
)
},
confirmButton = {
TextButton(onClick = {
onWalletConfigChange(walletConfig.copy(name = name))
showRenameDialog = false
}) {
Text("Rename")
}
},
)
}
}
}

View File

@ -11,6 +11,7 @@ import im.molly.monero.demo.common.asResult
import im.molly.monero.demo.data.WalletRepository
import im.molly.monero.demo.data.model.WalletConfig
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
class WalletViewModel(
private val walletId: Long,
@ -33,6 +34,12 @@ class WalletViewModel(
}
}
}
fun updateConfig(config: WalletConfig) {
viewModelScope.launch {
walletRepository.updateWalletConfig(config)
}
}
}
private fun walletUiState(