Skip to content
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
55 changes: 40 additions & 15 deletions app/src/main/java/com/joinself/app/demo/MainViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.joinself.app.demo

import android.content.Context
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.joinself.common.CredentialType
Expand All @@ -28,8 +27,11 @@ import java.io.File

private const val TAG = "MainViewModel"

private val appAddressKey = "ApplicationAddress"

sealed class InitializationState {
data object None: ServerState()
data object UnRegistered: InitializationState()
data object Loading: InitializationState()
data object Success: InitializationState()
data class Error(val message: String): InitializationState()
Expand Down Expand Up @@ -69,26 +71,28 @@ sealed class SERVER_REQUESTS {

// the main states of the app
data class AppUiState(
var isRegistered: Boolean = false,
// var isRegistered: Boolean = false,
var verificationStatus: Boolean = false,
var initialization: InitializationState = InitializationState.Loading,
var serverState: ServerState = ServerState.None,
var requestState: ServerRequestState = ServerRequestState.None,
var backupRestoreState: BackupRestoreState = BackupRestoreState.None
)

class MainViewModel(context: Context): ViewModel() {
class MainViewModel(val context: Context): ViewModel() {

private val sharedPreferences = context.getSharedPreferences("SelfDemoPref", Context.MODE_PRIVATE)

private val _appUiState = MutableStateFlow(AppUiState())
val appStateFlow: StateFlow<AppUiState> = _appUiState.asStateFlow()

val account: Account
var account: Account? = null
var serverInboxAddress: PublicKey? = null
private var groupAddress: PublicKey? = null
private var credentialRequest: CredentialRequest? = null
private var verificationRequest: VerificationRequest? = null
private var requestTimeoutJob: Job? = null
// private val receivedCredentials = mutableListOf<Credential>()


init {
// init the sdk
SelfSDK.initialize(
Expand All @@ -97,6 +101,17 @@ class MainViewModel(context: Context): ViewModel() {
log = { Timber.tag("SelfSDK").d(it) }
)

val appAddress = getApplicationAddress()
if (appAddress.isNotEmpty()) {
viewModelScope.launch(Dispatchers.IO) {
initAccount(appAddress)
}
} else {
_appUiState.update { it.copy(initialization = InitializationState.UnRegistered) }
}
}

suspend fun initAccount(applicationAddress: String, onConnectCompletion: (() -> Unit)? = null) {
// the sdk will store data in this directory, make sure it exists.
val storagePath = File(context.filesDir.absolutePath + "/account1")
if (!storagePath.exists()) storagePath.mkdirs()
Expand All @@ -106,6 +121,7 @@ class MainViewModel(context: Context): ViewModel() {
.setEnvironment(Environment.production)
.setSandbox(true)
.setStoragePath(storagePath.absolutePath)
.setApplicationAddress(applicationAddress)
.setCallbacks(object : Account.Callbacks {
override fun onMessage(message: Message) {
Timber.tag("DemoApp").d("onMessage: ${message.id()}")
Expand All @@ -132,6 +148,8 @@ class MainViewModel(context: Context): ViewModel() {
}
override fun onConnect() {
Timber.tag("DemoApp").d("onConnect")
onConnectCompletion?.invoke()

_appUiState.update {
it.copy(
initialization = InitializationState.Success
Expand All @@ -150,16 +168,16 @@ class MainViewModel(context: Context): ViewModel() {
})
.build()

_appUiState.update {
it.copy(
isRegistered = account.registered(),
)
}
// _appUiState.update {
// it.copy(
// isRegistered = account?.registered() ?: false,
// )
// }
}


fun isRegistered() : Boolean {
return account.registered()
return account?.registered() ?: false
}

// connect with server using an inbox address
Expand All @@ -168,7 +186,7 @@ class MainViewModel(context: Context): ViewModel() {
_appUiState.update { it.copy(serverState = ServerState.Connecting) }
serverInboxAddress = PublicKey(inboxAddress)

groupAddress = account.connectWith(serverInboxAddress!!, info = mapOf())
groupAddress = account?.connectWith(serverInboxAddress!!, info = mapOf())
if (groupAddress != null) {
_appUiState.update { it.copy(serverState = ServerState.Success) }
} else {
Expand All @@ -182,7 +200,7 @@ class MainViewModel(context: Context): ViewModel() {

suspend fun connect(inboxAddress: PublicKey, qrCode: ByteArray) {
try {
groupAddress = account.connectWith(qrCode)
groupAddress = account?.connectWith(qrCode)
serverInboxAddress = inboxAddress

if (groupAddress != null) {
Expand Down Expand Up @@ -221,7 +239,7 @@ class MainViewModel(context: Context): ViewModel() {
.build()

// send chat to server
val messageId = account.send(toAddress = serverInboxAddress!!, chat)
val messageId = account?.send(toAddress = serverInboxAddress!!, chat)
_appUiState.update { it.copy(requestState = ServerRequestState.RequestSent) }

startRequestTimeout()
Expand All @@ -241,4 +259,11 @@ class MainViewModel(context: Context): ViewModel() {
private fun cancelRequestTimeout() {
requestTimeoutJob?.cancel()
}

fun saveApplicationAddress(address: String) {
sharedPreferences.edit().putString(appAddressKey, address).apply()
}
fun getApplicationAddress(): String {
return sharedPreferences.getString(appAddressKey, "") ?: ""
}
}
54 changes: 40 additions & 14 deletions app/src/main/java/com/joinself/app/demo/SelfDemoApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
Expand All @@ -27,6 +28,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.joinself.app.demo.ui.screens.ApplicationAddressEnterScreen
import com.joinself.app.demo.ui.screens.AuthRequestResultScreen
import com.joinself.app.demo.ui.screens.AuthRequestStartScreen
import com.joinself.app.demo.ui.screens.BackupResultScreen
Expand Down Expand Up @@ -81,6 +83,7 @@ private const val TAG = "SelfSDKDemoApp"
sealed class MainRoute {
@Serializable object Initializing
@Serializable object Registration
@Serializable object EnterApplicationAddress
@Serializable object ConnectToServerSelection
@Serializable object ConnectToServerAddress
@Serializable object ConnectingToServer
Expand Down Expand Up @@ -155,6 +158,9 @@ fun SelfDemoApp(

LaunchedEffect(appState.initialization) {
when (val status = appState.initialization) {
is InitializationState.UnRegistered -> {
navController.navigate(MainRoute.Registration)
}
is InitializationState.Success -> {
val route = if (viewModel.isRegistered()) MainRoute.ConnectToServerSelection else MainRoute.Registration
navController.navigate(route)
Expand All @@ -171,11 +177,7 @@ fun SelfDemoApp(
RegistrationIntroScreen( selfModifier = selfModifier,
onStartRegistration = {
coroutineScope.launch {
viewModel.account.openRegistrationFlow { isSuccess, error ->
coroutineScope.launch(Dispatchers.Main) {
if (isSuccess) navController.navigate(MainRoute.ConnectToServerSelection)
}
}
navController.navigate(MainRoute.EnterApplicationAddress)
}
},
onStartRestore = {
Expand All @@ -184,14 +186,38 @@ fun SelfDemoApp(
onOpenSettings = onOpenSettings
)
}
composable<MainRoute.EnterApplicationAddress> {
ApplicationAddressEnterScreen(
onContinue = { address ->
coroutineScope.launch(Dispatchers.IO) {
viewModel.initAccount(
applicationAddress = address,
onConnectCompletion = {
coroutineScope.launch {
viewModel.account?.openRegistrationFlow { isSuccess, error ->
if (isSuccess) {
viewModel.saveApplicationAddress(address)

coroutineScope.launch(Dispatchers.Main) {
navController.navigate(MainRoute.ConnectToServerSelection)
}
}
}
}
}
)
}
}
)
}
composable<MainRoute.ConnectToServerSelection> {
ServerConnectSelectionScreen(
onAddress = {
navController.navigate(MainRoute.ConnectToServerAddress)
},
onQRCode = {
coroutineScope.launch {
viewModel.account.openQRCodeFlow(
viewModel.account?.openQRCodeFlow(
onFinish = { qrCode, discoveryData ->
if (discoveryData == null || !discoveryData.sandbox) {
return@openQRCodeFlow
Expand Down Expand Up @@ -298,7 +324,7 @@ fun SelfDemoApp(
) {
when(request) {
is CredentialRequest -> {
viewModel.account.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.account?.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.resetState(requestState = if (isSent) ServerRequestState.ResponseSent(status) else ServerRequestState.RequestError("failed to respond"))
})
}
Expand Down Expand Up @@ -352,7 +378,7 @@ fun SelfDemoApp(
VerifyEmailStartScreen(
onStartVerification = {
coroutineScope.launch {
viewModel.account.openEmailVerificationFlow(onFinish = { isSuccess, error ->
viewModel.account?.openEmailVerificationFlow(onFinish = { isSuccess, error ->
viewModel.resetState(verificationStatus = isSuccess)
navController.navigate(MainRoute.VerifyEmailResult)
})
Expand All @@ -372,7 +398,7 @@ fun SelfDemoApp(
VerifyDocumentStartScreen(
onStartVerification = {
coroutineScope.launch {
viewModel.account.openDocumentVerificationFlow(
viewModel.account?.openDocumentVerificationFlow(
isDevMode = false,
onFinish = { isSuccess, error ->
viewModel.resetState(verificationStatus = isSuccess)
Expand Down Expand Up @@ -411,7 +437,7 @@ fun SelfDemoApp(
) {
when(request) {
is CredentialMessage -> {
viewModel.account.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.account?.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.resetState(requestState = if (isSent) ServerRequestState.ResponseSent(status) else ServerRequestState.RequestError("failed to respond"))
})
}
Expand Down Expand Up @@ -494,7 +520,7 @@ fun SelfDemoApp(
) {
when(request) {
is CredentialRequest -> {
viewModel.account.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.account?.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.resetState(requestState = if (isSent) ServerRequestState.ResponseSent(status) else ServerRequestState.RequestError("failed to respond"))
})
}
Expand Down Expand Up @@ -552,7 +578,7 @@ fun SelfDemoApp(
) {
when(request) {
is VerificationRequest -> {
viewModel.account.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.account?.DisplayRequestUI(selfModifier, request, onFinish = { isSent, status ->
viewModel.resetState(requestState = if (isSent) ServerRequestState.ResponseSent(status) else ServerRequestState.RequestError("failed to respond"))
})
}
Expand Down Expand Up @@ -593,7 +619,7 @@ fun SelfDemoApp(
backupState = appState.backupRestoreState,
onStartBackup = {
coroutineScope.launch(Dispatchers.Main) {
viewModel.account.openBackupFlow(onFinish = { isSuccess, error ->
viewModel.account?.openBackupFlow(onFinish = { isSuccess, error ->
if (isSuccess) {
viewModel.setBackupRestoreState(state = BackupRestoreState.Success)
} else {
Expand Down Expand Up @@ -621,7 +647,7 @@ fun SelfDemoApp(
restoreState = appState.backupRestoreState,
onStartRestore = {
coroutineScope.launch(Dispatchers.Main) {
viewModel.account.openRestoreFlow(onFinish = { isSuccess, error ->
viewModel.account?.openRestoreFlow(onFinish = { isSuccess, error ->
if (isSuccess) {
viewModel.setBackupRestoreState(state = BackupRestoreState.Success)
} else {
Expand Down
Loading