diff --git a/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt b/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt index 4e0ef30e51449ab292acc320f4aad459e5ba71d8..d4dcded3a9005e1514a1f207cca59f0a0fdffb2c 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/BriarDesktopApp.kt @@ -18,7 +18,7 @@ import javax.inject.Singleton @Singleton internal interface BriarDesktopApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons { - fun getUI(): UI + fun getBriarUi(): BriarUi fun getSecureRandom(): SecureRandom } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt b/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt deleted file mode 100644 index 68093730fb08db1c66f87ecb275f017a001649b8..0000000000000000000000000000000000000000 --- a/src/main/kotlin/org/briarproject/briar/desktop/BriarService.kt +++ /dev/null @@ -1,157 +0,0 @@ -package org.briarproject.briar.desktop - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.compositionLocalOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.window.Window -import org.briarproject.bramble.api.account.AccountManager -import org.briarproject.bramble.api.contact.Contact -import org.briarproject.bramble.api.contact.ContactManager -import org.briarproject.bramble.api.crypto.DecryptionException -import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator -import org.briarproject.bramble.api.identity.IdentityManager -import org.briarproject.bramble.api.lifecycle.LifecycleManager -import org.briarproject.briar.api.conversation.ConversationManager -import org.briarproject.briar.api.messaging.MessagingManager -import org.briarproject.briar.desktop.dialogs.Login -import org.briarproject.briar.desktop.dialogs.Registration -import org.briarproject.briar.desktop.paul.theme.BriarTheme -import org.briarproject.briar.desktop.paul.views.BriarUIStateManager -import java.awt.Dimension -import java.util.logging.Logger -import javax.annotation.concurrent.Immutable -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.system.exitProcess - -enum class Screen { - REGISTRATION, - LOGIN, - MAIN -} - -interface BriarService { - @Composable - fun start( - contactManager: ContactManager, - conversationManager: ConversationManager, - messagingManager: MessagingManager, - identityManager: IdentityManager, - ) - - fun stop() -} - -val CVM = compositionLocalOf<ConversationManager> { error("Undefined ConversationManager") } -val CTM = compositionLocalOf<ContactManager> { error("Undefined ContactManager") } -val MM = compositionLocalOf<MessagingManager> { error("Undefined MessagingManager") } -val IM = compositionLocalOf<IdentityManager> { error("Undefined IdentityManager") } - -@Immutable -@Singleton -internal class BriarServiceImpl -@Inject -constructor( - private val accountManager: AccountManager, - private val contactManager: ContactManager, - private val messagingManager: MessagingManager, - private val lifecycleManager: LifecycleManager, - private val passwordStrengthEstimator: PasswordStrengthEstimator -) : BriarService { - - companion object { - private val LOG = Logger.getLogger(BriarServiceImpl::class.java.name) - } - - private val contacts: MutableList<Contact> = ArrayList() - - override fun stop() { - lifecycleManager.stopServices() - lifecycleManager.waitForShutdown() - } - - @Composable - override fun start( - contactManager: ContactManager, - conversationManager: ConversationManager, - messagingManager: MessagingManager, - identityManager: IdentityManager, - ) { - val (isDark, setDark) = remember { mutableStateOf(true) } - val title = "Briar Desktop" - var screenState by remember { - mutableStateOf( - if (accountManager.hasDatabaseKey()) { - // this should only happen during testing when we launch the main UI directly - // without a need to enter the password. - loadContacts() - Screen.MAIN - } else if (accountManager.accountExists()) { - Screen.LOGIN - } else { - Screen.REGISTRATION - } - ) - } - Window( - title = title, - onCloseRequest = { exitProcess(0) }, - ) { - window.minimumSize = Dimension(800, 600) - BriarTheme(isDarkTheme = isDark) { - when (screenState) { - Screen.REGISTRATION -> - Registration( - onSubmit = { username, password -> - accountManager.createAccount(username, password) - signedIn() - loadContacts() - screenState = Screen.MAIN - } - ) - Screen.LOGIN -> - Login( - onResult = { - try { - accountManager.signIn(it) - signedIn() - loadContacts() - screenState = Screen.MAIN - } catch (e: DecryptionException) { - // failure, try again - } - } - ) - - else -> - CompositionLocalProvider( - CVM provides conversationManager, - CTM provides contactManager, - MM provides messagingManager, - IM provides identityManager, - ) { - BriarUIStateManager(contacts, isDark, setDark) - } - } - } - } - } - - private fun signedIn() { - val dbKey = accountManager.databaseKey ?: throw AssertionError() - lifecycleManager.startServices(dbKey) - lifecycleManager.waitForStartup() - } - - private fun loadContacts() { - val contacts = contactManager.contacts - for (contact in contacts) { - LOG.info("loaded contact: ${contact.author.name} (${contact.alias})") - this.contacts.add(contact) - } - } -} diff --git a/src/main/kotlin/org/briarproject/briar/desktop/BriarUi.kt b/src/main/kotlin/org/briarproject/briar/desktop/BriarUi.kt new file mode 100644 index 0000000000000000000000000000000000000000..52f9fa36d23b04765842638344bb7e4ade6d588a --- /dev/null +++ b/src/main/kotlin/org/briarproject/briar/desktop/BriarUi.kt @@ -0,0 +1,126 @@ +package org.briarproject.briar.desktop + +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import org.briarproject.bramble.api.account.AccountManager +import org.briarproject.bramble.api.contact.ContactManager +import org.briarproject.bramble.api.identity.IdentityManager +import org.briarproject.bramble.api.lifecycle.LifecycleManager +import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING +import org.briarproject.briar.api.conversation.ConversationManager +import org.briarproject.briar.api.messaging.MessagingManager +import org.briarproject.briar.desktop.dialogs.ContactsViewModel +import org.briarproject.briar.desktop.dialogs.Login +import org.briarproject.briar.desktop.dialogs.LoginViewModel +import org.briarproject.briar.desktop.dialogs.Registration +import org.briarproject.briar.desktop.dialogs.RegistrationViewModel +import org.briarproject.briar.desktop.paul.theme.BriarTheme +import org.briarproject.briar.desktop.paul.views.BriarUIStateManager +import java.awt.Dimension +import java.util.logging.Logger +import javax.annotation.concurrent.Immutable +import javax.inject.Inject +import javax.inject.Singleton + +enum class Screen { + REGISTRATION, + LOGIN, + MAIN +} + +interface BriarUi { + + fun start() + + fun stop() +} + +val CVM = compositionLocalOf<ConversationManager> { error("Undefined ConversationManager") } +val CTM = compositionLocalOf<ContactManager> { error("Undefined ContactManager") } +val MM = compositionLocalOf<MessagingManager> { error("Undefined MessagingManager") } +val IM = compositionLocalOf<IdentityManager> { error("Undefined IdentityManager") } + +@Immutable +@Singleton +internal class BriarUiImpl +@Inject +constructor( + private val registrationViewModel: RegistrationViewModel, + private val loginViewModel: LoginViewModel, + private val contactsViewModel: ContactsViewModel, + private val accountManager: AccountManager, + private val contactManager: ContactManager, + private val conversationManager: ConversationManager, + private val identityManager: IdentityManager, + private val messagingManager: MessagingManager, + private val lifecycleManager: LifecycleManager, +) : BriarUi { + + companion object { + private val LOG = Logger.getLogger(BriarUiImpl::class.java.name) + } + + override fun stop() { + // TODO: check how briar is doing this + if (lifecycleManager.lifecycleState == RUNNING) { + lifecycleManager.stopServices() + lifecycleManager.waitForShutdown() + } + } + + override fun start() { + application { + val (isDark, setDark) = remember { mutableStateOf(true) } + val title = "Briar Desktop" + var screenState by remember { + mutableStateOf( + if (accountManager.hasDatabaseKey()) { + // this should only happen during testing when we launch the main UI directly + // without a need to enter the password. + contactsViewModel.loadContacts() + Screen.MAIN + } else if (accountManager.accountExists()) { + Screen.LOGIN + } else { + Screen.REGISTRATION + } + ) + } + Window( + title = title, + onCloseRequest = { stop(); exitApplication() }, + ) { + window.minimumSize = Dimension(800, 600) + BriarTheme(isDarkTheme = isDark) { + when (screenState) { + Screen.REGISTRATION -> + Registration(registrationViewModel) { + contactsViewModel.loadContacts() + screenState = Screen.MAIN + } + Screen.LOGIN -> + Login(loginViewModel) { + contactsViewModel.loadContacts() + screenState = Screen.MAIN + } + else -> + CompositionLocalProvider( + CVM provides conversationManager, + CTM provides contactManager, + MM provides messagingManager, + IM provides identityManager, + ) { + BriarUIStateManager(contactsViewModel, isDark, setDark) + } + } + } + } + } + } +} diff --git a/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt b/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt index aaa11bb431b10935b96894e55c1e109fd4be7d76..7a55917cd28a774785de504291c8dd6dc4895ba8 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/DesktopModule.kt @@ -48,7 +48,7 @@ internal class DesktopModule(private val appDir: Path) { @Provides @Singleton - internal fun provideBriarService(briarService: BriarServiceImpl): BriarService = briarService + internal fun provideBriarService(briarService: BriarUiImpl): BriarUi = briarService @Provides @Singleton diff --git a/src/main/kotlin/org/briarproject/briar/desktop/Main.kt b/src/main/kotlin/org/briarproject/briar/desktop/Main.kt index 5a4e72ec8597505b4503779cfd44a47a0bafc3d4..1c401a2cfc3fbcdd11e814673272a4bd9b6ccacd 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/Main.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/Main.kt @@ -1,7 +1,6 @@ package org.briarproject.briar.desktop import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.window.application import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.options.counted import com.github.ajalt.clikt.parameters.options.default @@ -42,7 +41,7 @@ private class Main : CliktCommand( ).default(DEFAULT_DATA_DIR) @OptIn(ExperimentalComposeUiApi::class) - override fun run() = application { + override fun run() { val level = if (debug) ALL else when (verbosity) { 0 -> WARNING 1 -> INFO @@ -61,7 +60,7 @@ private class Main : CliktCommand( BrambleCoreEagerSingletons.Helper.injectEagerSingletons(app) BriarCoreEagerSingletons.Helper.injectEagerSingletons(app) - app.getUI().startBriar() + app.getBriarUi().start() } private fun getDataDir(): Path { diff --git a/src/main/kotlin/org/briarproject/briar/desktop/UI.kt b/src/main/kotlin/org/briarproject/briar/desktop/UI.kt deleted file mode 100644 index f12d0c60dcd211072ecd736c187f2f3bd0dfba88..0000000000000000000000000000000000000000 --- a/src/main/kotlin/org/briarproject/briar/desktop/UI.kt +++ /dev/null @@ -1,46 +0,0 @@ -package org.briarproject.briar.desktop - -import androidx.compose.runtime.Composable -import org.briarproject.bramble.api.account.AccountManager -import org.briarproject.bramble.api.contact.ContactManager -import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator -import org.briarproject.bramble.api.event.EventBus -import org.briarproject.bramble.api.identity.IdentityManager -import org.briarproject.briar.api.conversation.ConversationManager -import org.briarproject.briar.api.introduction.IntroductionManager -import org.briarproject.briar.api.messaging.MessagingManager -import org.briarproject.briar.api.messaging.PrivateMessageFactory -import java.util.logging.Logger.getLogger -import javax.annotation.concurrent.Immutable -import javax.inject.Inject -import javax.inject.Singleton - -@Immutable -@Singleton -internal class UI -@Inject -constructor( - private val briarService: BriarService, - private val accountManager: AccountManager, - private val contactManager: ContactManager, - private val messagingManager: MessagingManager, - private val introductionManager: IntroductionManager, - private val conversationManager: ConversationManager, - private val identityManager: IdentityManager, - private val privateMessageFactory: PrivateMessageFactory, - private val eventBus: EventBus, - private val passwordStrengthEstimator: PasswordStrengthEstimator -) { - - private val logger = getLogger(UI::javaClass.name) - - @Composable - internal fun startBriar() { - briarService.start( - contactManager, - conversationManager, - messagingManager, - identityManager - ) - } -} diff --git a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/ContactsViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/ContactsViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..194155a15845287818e8c7197182447571fbbfa4 --- /dev/null +++ b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/ContactsViewModel.kt @@ -0,0 +1,28 @@ +package org.briarproject.briar.desktop.dialogs + +import androidx.compose.runtime.mutableStateListOf +import org.briarproject.bramble.api.contact.Contact +import org.briarproject.bramble.api.contact.ContactManager +import java.util.logging.Logger +import javax.inject.Inject + +class ContactsViewModel +@Inject +constructor( + private val contactManager: ContactManager, +) { + + companion object { + private val LOG = Logger.getLogger(ContactsViewModel::class.java.name) + } + + internal val contacts = mutableStateListOf<Contact>() + + internal fun loadContacts() { + val contacts = contactManager.contacts + for (contact in contacts) { + LOG.info("loaded contact: ${contact.author.name} (${contact.alias})") + this.contacts.add(contact) + } + } +} diff --git a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt index 7be9e7caca821cedc3d161b3a9740e8ae6937ea7..a61f33837cd4a0e951f45f518c39992595e0eb5c 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Login.kt @@ -17,10 +17,7 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -42,10 +39,16 @@ import androidx.compose.ui.unit.dp @OptIn(ExperimentalComposeUiApi::class) @Composable fun Login( + viewModel: LoginViewModel, modifier: Modifier = Modifier, - onResult: (result: String) -> Unit + onSignedIn: () -> Unit ) { - var password by remember { mutableStateOf("") } + val signIn = { + viewModel.signIn { + onSignedIn() + } + } + val initialFocusRequester = remember { FocusRequester() } Surface { Column( @@ -56,24 +59,24 @@ fun Login( BriarLogo() Spacer(Modifier.height(32.dp)) OutlinedTextField( - value = password, - onValueChange = { password = it }, + value = viewModel.password.value, + onValueChange = viewModel::setPassword, label = { Text("Password") }, singleLine = true, visualTransformation = PasswordVisualTransformation(), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), - keyboardActions = KeyboardActions(onDone = { onResult.invoke(password) }), + keyboardActions = KeyboardActions(onDone = { signIn() }), modifier = Modifier .focusRequester(initialFocusRequester) .onPreviewKeyEvent { if (it.type == KeyEventType.KeyUp && it.key == Key.Enter) { - onResult.invoke(password) + signIn() } false }, ) Spacer(Modifier.height(16.dp)) - Button(onClick = { onResult.invoke(password) }) { + Button(onClick = { signIn() }) { Text("Login") } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/LoginViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/LoginViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..228a8012197763b092fd5c0e3fe213dcf0f382df --- /dev/null +++ b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/LoginViewModel.kt @@ -0,0 +1,40 @@ +package org.briarproject.briar.desktop.dialogs + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import org.briarproject.bramble.api.account.AccountManager +import org.briarproject.bramble.api.crypto.DecryptionException +import org.briarproject.bramble.api.lifecycle.LifecycleManager +import javax.inject.Inject + +class LoginViewModel +@Inject +constructor( + private val accountManager: AccountManager, + private val lifecycleManager: LifecycleManager, +) { + + private val _password = mutableStateOf("") + + val password: State<String> = _password + + fun setPassword(password: String) { + _password.value = password + } + + fun signIn(success: () -> Unit) { + try { + accountManager.signIn(password.value) + signedIn() + success() + } catch (e: DecryptionException) { + // failure, try again + } + } + + private fun signedIn() { + val dbKey = accountManager.databaseKey ?: throw AssertionError() + lifecycleManager.startServices(dbKey) + lifecycleManager.waitForStartup() + } +} diff --git a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Registration.kt b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Registration.kt index afab8ce46adc62a904ffdb9638ae118cd411ad41..7cc06944c6aa53ab3f8b69aad27363c6248750db 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Registration.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/Registration.kt @@ -10,13 +10,11 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Button import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -40,61 +38,68 @@ import androidx.compose.ui.unit.dp @OptIn(ExperimentalComposeUiApi::class) @Composable fun Registration( + viewModel: RegistrationViewModel, modifier: Modifier = Modifier, - onSubmit: (username: String, password: String) -> Unit + onSignedUp: () -> Unit ) { - var username by remember { mutableStateOf("") } - var password by remember { mutableStateOf("") } + val signUp = { + viewModel.signUp { + onSignedUp() + } + } + val initialFocusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current - Column( - modifier = modifier.padding(16.dp).fillMaxSize(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - BriarLogo() - Spacer(Modifier.height(32.dp)) - OutlinedTextField( - value = username, - onValueChange = { username = it }, - label = { Text("Username") }, - singleLine = true, - textStyle = TextStyle(color = Color.White), - keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), - keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) }), - modifier = Modifier - .focusRequester(initialFocusRequester) - .onPreviewKeyEvent { + Surface { + Column( + modifier = modifier.padding(16.dp).fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + BriarLogo() + Spacer(Modifier.height(32.dp)) + OutlinedTextField( + value = viewModel.username.value, + onValueChange = { viewModel.setUsername(it) }, + label = { Text("Username") }, + singleLine = true, + textStyle = TextStyle(color = Color.White), + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) }), + modifier = Modifier + .focusRequester(initialFocusRequester) + .onPreviewKeyEvent { + if (it.type == KeyEventType.KeyUp && it.key == Key.Enter) { + focusManager.moveFocus(FocusDirection.Next) + } + false + }, + ) + OutlinedTextField( + value = viewModel.password.value, + onValueChange = { viewModel.setPassword(it) }, + label = { Text("Password") }, + singleLine = true, + textStyle = TextStyle(color = Color.White), + visualTransformation = PasswordVisualTransformation(), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = { signUp() }), + modifier = Modifier.onPreviewKeyEvent { if (it.type == KeyEventType.KeyUp && it.key == Key.Enter) { - focusManager.moveFocus(FocusDirection.Next) + signUp() } false }, - ) - OutlinedTextField( - value = password, - onValueChange = { password = it }, - label = { Text("Password") }, - singleLine = true, - textStyle = TextStyle(color = Color.White), - visualTransformation = PasswordVisualTransformation(), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), - keyboardActions = KeyboardActions(onDone = { onSubmit.invoke(username, password) }), - modifier = Modifier.onPreviewKeyEvent { - if (it.type == KeyEventType.KeyUp && it.key == Key.Enter) { - onSubmit.invoke(username, password) - } - false - }, - ) - Spacer(Modifier.height(16.dp)) - Button(onClick = { onSubmit.invoke(username, password) }) { - Text("Register", color = Color.Black) - } + ) + Spacer(Modifier.height(16.dp)) + Button(onClick = { signUp() }) { + Text("Register", color = Color.Black) + } - DisposableEffect(Unit) { - initialFocusRequester.requestFocus() - onDispose { } + DisposableEffect(Unit) { + initialFocusRequester.requestFocus() + onDispose { } + } } } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/dialogs/RegistrationViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/RegistrationViewModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..b5a9b016e02a2ef18ee3b383285bc749e2ea60e6 --- /dev/null +++ b/src/main/kotlin/org/briarproject/briar/desktop/dialogs/RegistrationViewModel.kt @@ -0,0 +1,46 @@ +package org.briarproject.briar.desktop.dialogs + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import org.briarproject.bramble.api.account.AccountManager +import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator +import org.briarproject.bramble.api.lifecycle.LifecycleManager +import javax.inject.Inject + +class RegistrationViewModel +@Inject +constructor( + private val accountManager: AccountManager, + private val lifecycleManager: LifecycleManager, + private val passwordStrengthEstimator: PasswordStrengthEstimator, +) { + + private var isSafeEnough = mutableStateOf(false) + private val _username = mutableStateOf("") + private val _password = mutableStateOf("") + + val username: State<String> = _username + val password: State<String> = _password + + fun setUsername(username: String) { + _username.value = username + } + + fun setPassword(password: String) { + _password.value = password + // TODO: decide on useful value here + isSafeEnough.value = passwordStrengthEstimator.estimateStrength(password) > 0 + } + + fun signUp(success: () -> Unit) { + accountManager.createAccount(_username.value, _password.value) + signedIn() + success() + } + + private fun signedIn() { + val dbKey = accountManager.databaseKey ?: throw AssertionError() + lifecycleManager.startServices(dbKey) + lifecycleManager.waitForStartup() + } +} diff --git a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt index 3babe30d44caa4dd82254063e75c54cd64e9b5b1..d8699185fe69987793dbac0c4a821bb7c4babe4d 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/BriarUIStateManager.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import org.briarproject.bramble.api.contact.Contact +import org.briarproject.briar.desktop.dialogs.ContactsViewModel enum class UiModes { CONTACTS, @@ -31,7 +32,7 @@ enum class UiModes { */ @Composable fun BriarUIStateManager( - contacts: List<Contact>, + contactsViewModel: ContactsViewModel, isDark: Boolean, setDark: (Boolean) -> Unit ) { @@ -39,9 +40,9 @@ fun BriarUIStateManager( val (uiMode, setUiMode) = remember { mutableStateOf(UiModes.CONTACTS) } // TODO Figure out how to handle accounts with 0 contacts // current selected contact - val (contact, setContact) = remember { mutableStateOf(contact(contacts)) } + val (contact, setContact) = remember { mutableStateOf(contact(contactsViewModel)) } // current selected private group - val (group, setGroup) = remember { mutableStateOf(contact(contacts)) } + val (group, setGroup) = remember { mutableStateOf(contact(contactsViewModel)) } // current selected forum val (forum, setForum) = remember { mutableStateOf(0) } // current blog state @@ -57,7 +58,7 @@ fun BriarUIStateManager( when (uiMode) { UiModes.CONTACTS -> if (contact != null) PrivateMessageView( contact, - contacts, + contactsViewModel, setContact ) UiModes.SETTINGS -> PlaceHolderSettingsView(isDark, setDark) @@ -79,6 +80,6 @@ fun PlaceHolderSettingsView(isDark: Boolean, setDark: (Boolean) -> Unit) { } } -fun contact(contacts: List<Contact>): Contact? { - return if (contacts.isEmpty()) null else contacts[0] +fun contact(contacts: ContactsViewModel): Contact? { + return if (contacts.contacts.isEmpty()) null else contacts.contacts[0] } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt index fcadca087dd27e32090fa7b2949ab76514ac692f..a05d9cae64e0d171be6911dda7ef1e62d8443634 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/paul/views/PrivateMessageView.kt @@ -88,6 +88,7 @@ import org.briarproject.briar.desktop.chat.ChatHistoryConversationVisitor import org.briarproject.briar.desktop.chat.ConversationMessageHeaderComparator import org.briarproject.briar.desktop.chat.SimpleMessage import org.briarproject.briar.desktop.chat.UiState +import org.briarproject.briar.desktop.dialogs.ContactsViewModel import org.briarproject.briar.desktop.paul.theme.DarkColors import org.briarproject.briar.desktop.paul.theme.awayMsgBubble import org.briarproject.briar.desktop.paul.theme.divider @@ -127,7 +128,7 @@ fun VerticalDivider() { @Composable fun PrivateMessageView( contact: Contact, - contacts: List<Contact>, + contacts: ContactsViewModel, onContactSelect: (Contact) -> Unit ) { val (isDialogVisible, setDialogVisibility) = remember { mutableStateOf(false) } @@ -136,12 +137,12 @@ fun PrivateMessageView( val (contactDrawerState, setDrawerState) = remember { mutableStateOf(ContactInfoDrawerState.MakeIntro) } AddContactDialog(isDialogVisible, setDialogVisibility) Row(modifier = Modifier.fillMaxWidth()) { - ContactList(contact, contacts, onContactSelect, setDialogVisibility) + ContactList(contact, contacts.contacts, onContactSelect, setDialogVisibility) VerticalDivider() Column(modifier = Modifier.weight(1f).fillMaxHeight()) { Conversation( contact, - contacts, + contacts.contacts, dropdownExpanded, setExpanded, infoDrawer, diff --git a/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt b/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt index dd1f8ca9f4c442b752ae90be9583ff946672c5af..7265ea99041803a6139439011b07b5a10791fbfe 100644 --- a/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt +++ b/src/test/kotlin/org/briarproject/briar/desktop/BriarDesktopTestApp.kt @@ -23,7 +23,7 @@ import javax.inject.Singleton @Singleton internal interface BriarDesktopTestApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons { - fun getUI(): UI + fun getBriarUi(): BriarUi fun getSecureRandom(): SecureRandom diff --git a/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt b/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt index cebf66dfaaeb9251699e49a1da429448cf10c560..dde9e5483f3bc1714a68b7d623029bb923ff4164 100644 --- a/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt +++ b/src/test/kotlin/org/briarproject/briar/desktop/DesktopTestModule.kt @@ -52,7 +52,7 @@ internal class DesktopTestModule(private val appDir: File) { @Provides @Singleton - internal fun provideBriarService(briarService: BriarServiceImpl): BriarService = briarService + internal fun provideBriarService(briarService: BriarUiImpl): BriarUi = briarService @Provides @Singleton diff --git a/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt b/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt index d7860028a8e2b074153bfd928e0e6b668e74c7db..e3375e8483d8f4f6e302b7cfc8c36f60a0dd0f49 100644 --- a/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt +++ b/src/test/kotlin/org/briarproject/briar/desktop/RunWithTemporaryAccount.kt @@ -56,7 +56,7 @@ internal class RunWithTemporaryAccount(val customization: BriarDesktopTestApp.() // list yet, we need to wait a moment in order for that to finish (hopefully). Thread.sleep(1000) - app.getUI().startBriar() + app.getBriarUi().start() } private fun getDataDir(): Path {