Handle backpresses in onboarding

pull/1554/head
bemusementpark 10 months ago
parent d621036af6
commit 9cf3a37a2b

@ -18,6 +18,7 @@ package org.thoughtcrime.securesms;
import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant; import static nl.komponents.kovenant.android.KovenantAndroid.startKovenant;
import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant; import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant;
import android.annotation.SuppressLint;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -137,7 +138,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
public MessageNotifier messageNotifier = null; public MessageNotifier messageNotifier = null;
public Poller poller = null; public Poller poller = null;
public Broadcaster broadcaster = null; public Broadcaster broadcaster = null;
private Job firebaseInstanceIdJob;
private WindowDebouncer conversationListDebouncer; private WindowDebouncer conversationListDebouncer;
private HandlerThread conversationListHandlerThread; private HandlerThread conversationListHandlerThread;
private Handler conversationListHandler; private Handler conversationListHandler;
@ -504,17 +504,9 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
}); });
} }
public void clearAllData(boolean isMigratingToV2KeyPair) { @SuppressLint("ApplySharedPref")
if (firebaseInstanceIdJob != null && firebaseInstanceIdJob.isActive()) { public void clearAllData() {
firebaseInstanceIdJob.cancel(null);
}
String displayName = TextSecurePreferences.getProfileName(this);
boolean isUsingFCM = TextSecurePreferences.isPushEnabled(this);
TextSecurePreferences.clearAll(this); TextSecurePreferences.clearAll(this);
if (isMigratingToV2KeyPair) {
TextSecurePreferences.setPushEnabled(this, isUsingFCM);
TextSecurePreferences.setProfileName(this, displayName);
}
getSharedPreferences(PREFERENCES_NAME, 0).edit().clear().commit(); getSharedPreferences(PREFERENCES_NAME, 0).edit().clear().commit();
if (!deleteDatabase(SQLCipherOpenHelper.DATABASE_NAME)) { if (!deleteDatabase(SQLCipherOpenHelper.DATABASE_NAME)) {
Log.d("Loki", "Failed to delete database."); Log.d("Loki", "Failed to delete database.");

@ -82,13 +82,13 @@ internal fun LandingScreen(
text = stringResource(R.string.urlOpenBrowser), text = stringResource(R.string.urlOpenBrowser),
buttons = listOf( buttons = listOf(
DialogButtonModel( DialogButtonModel(
GetString(R.string.activity_landing_terms_of_service), text = GetString(R.string.activity_landing_terms_of_service),
GetString(R.string.AccessibilityId_terms_of_service_button), contentDescription = GetString(R.string.AccessibilityId_terms_of_service_button),
onClick = openTerms onClick = openTerms
), ),
DialogButtonModel( DialogButtonModel(
GetString(R.string.activity_landing_privacy_policy), text = GetString(R.string.activity_landing_privacy_policy),
GetString(R.string.AccessibilityId_privacy_policy_button), contentDescription = GetString(R.string.AccessibilityId_privacy_policy_button),
onClick = openPrivacyPolicy onClick = openPrivacyPolicy
) )
) )

@ -32,10 +32,7 @@ class LandingActivity: BaseActionBarActivity() {
setComposeContent { setComposeContent {
LandingScreen( LandingScreen(
createAccount = { createAccount = { startPickDisplayNameActivity() },
prefs.setHasViewedSeed(false)
startPickDisplayNameActivity()
},
loadAccount = { start<LoadAccountActivity>() }, loadAccount = { start<LoadAccountActivity>() },
openTerms = { open("https://getsession.org/terms-of-service") }, openTerms = { open("https://getsession.org/terms-of-service") },
openPrivacyPolicy = { open("https://getsession.org/privacy-policy") } openPrivacyPolicy = { open("https://getsession.org/privacy-policy") }

@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.onboarding.loadaccount
import android.os.Bundle import android.os.Bundle
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.camera.core.ExperimentalGetImage
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -11,14 +10,13 @@ import kotlinx.coroutines.launch
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.onboarding.loading.LoadingManager import org.thoughtcrime.securesms.onboarding.manager.LoadingManager
import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsActivity import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsActivity
import org.thoughtcrime.securesms.ui.setComposeContent import org.thoughtcrime.securesms.ui.setComposeContent
import org.thoughtcrime.securesms.util.start import org.thoughtcrime.securesms.util.start
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@androidx.annotation.OptIn(ExperimentalGetImage::class)
class LoadAccountActivity : BaseActionBarActivity() { class LoadAccountActivity : BaseActionBarActivity() {
@Inject @Inject
@ -31,7 +29,6 @@ class LoadAccountActivity : BaseActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
supportActionBar?.setTitle(R.string.activity_link_load_account) supportActionBar?.setTitle(R.string.activity_link_load_account)
prefs.setHasViewedSeed(true)
prefs.setConfigurationMessageSynced(false) prefs.setConfigurationMessageSynced(false)
prefs.setRestorationTime(System.currentTimeMillis()) prefs.setRestorationTime(System.currentTimeMillis())
prefs.setLastProfileUpdateTime(0) prefs.setLastProfileUpdateTime(0)

@ -28,11 +28,6 @@ class LoadingActivity: BaseActionBarActivity() {
private val viewModel: LoadingViewModel by viewModels() private val viewModel: LoadingViewModel by viewModels()
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
return
}
private fun register(loadFailed: Boolean) { private fun register(loadFailed: Boolean) {
prefs.setLastConfigurationSyncTime(System.currentTimeMillis()) prefs.setLastConfigurationSyncTime(System.currentTimeMillis())
@ -47,6 +42,8 @@ class LoadingActivity: BaseActionBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setUpActionBarSessionLogo()
ApplicationContext.getInstance(this).newAccount = false ApplicationContext.getInstance(this).newAccount = false
setComposeContent { setComposeContent {
@ -54,8 +51,6 @@ class LoadingActivity: BaseActionBarActivity() {
LoadingScreen(state) LoadingScreen(state)
} }
setUpActionBarSessionLogo(true)
lifecycleScope.launch { lifecycleScope.launch {
viewModel.events.collect { viewModel.events.collect {
when (it) { when (it) {

@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.onboarding.loading package org.thoughtcrime.securesms.onboarding.manager
import android.content.Context import android.content.Context
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

@ -31,7 +31,11 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsViewModel.UiState
import org.thoughtcrime.securesms.onboarding.ui.ContinuePrimaryOutlineButton import org.thoughtcrime.securesms.onboarding.ui.ContinuePrimaryOutlineButton
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.LocalDimensions import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.PreviewTheme import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider
@ -39,6 +43,7 @@ import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.color.Colors import org.thoughtcrime.securesms.ui.color.Colors
import org.thoughtcrime.securesms.ui.color.LocalColors import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.transparentButtonColors import org.thoughtcrime.securesms.ui.color.transparentButtonColors
import org.thoughtcrime.securesms.ui.components.CircularProgressIndicator
import org.thoughtcrime.securesms.ui.contentDescription import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.h4 import org.thoughtcrime.securesms.ui.h4
import org.thoughtcrime.securesms.ui.h8 import org.thoughtcrime.securesms.ui.h8
@ -47,10 +52,39 @@ import org.thoughtcrime.securesms.ui.small
@Composable @Composable
internal fun MessageNotificationsScreen( internal fun MessageNotificationsScreen(
state: MessageNotificationsState = MessageNotificationsState(), state: UiState = UiState(),
setEnabled: (Boolean) -> Unit = {}, setEnabled: (Boolean) -> Unit = {},
onContinue: () -> Unit = {} onContinue: () -> Unit = {},
quit: () -> Unit = {},
dismissDialog: () -> Unit = {}
) { ) {
if (state.clearData) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(LocalColors.current.primary)
}
return
}
if (state.showDialog) AlertDialog(
onDismissRequest = dismissDialog,
title = stringResource(R.string.warning),
text = stringResource(R.string.you_cannot_go_back_further_in_order_to_stop_loading_your_account_session_needs_to_quit),
buttons = listOf(
DialogButtonModel(
GetString(stringResource(R.string.quit)),
color = LocalColors.current.danger,
onClick = quit
),
DialogButtonModel(
GetString(stringResource(R.string.cancel))
)
)
)
Column { Column {
Spacer(Modifier.weight(1f)) Spacer(Modifier.weight(1f))
@ -105,9 +139,15 @@ private fun NotificationRadioButton(
Box( Box(
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.border(LocalDimensions.current.borderStroke, LocalColors.current.borders, RoundedCornerShape(8.dp)), .border(
LocalDimensions.current.borderStroke,
LocalColors.current.borders,
RoundedCornerShape(8.dp)
),
) { ) {
Column(modifier = Modifier.padding(horizontal = 15.dp).padding(top = 10.dp, bottom = 11.dp)) { Column(modifier = Modifier
.padding(horizontal = 15.dp)
.padding(top = 10.dp, bottom = 11.dp)) {
Text(stringResource(title), style = h8) Text(stringResource(title), style = h8)
Text(stringResource(explanation), style = small, modifier = Modifier.padding(top = 7.dp)) Text(stringResource(explanation), style = small, modifier = Modifier.padding(top = 7.dp))
@ -139,7 +179,9 @@ private fun RadioButtonIndicator(
Box(modifier = modifier) { Box(modifier = modifier) {
AnimatedVisibility( AnimatedVisibility(
selected, selected,
modifier = Modifier.padding(2.5.dp).clip(CircleShape), modifier = Modifier
.padding(2.5.dp)
.clip(CircleShape),
enter = scaleIn(), enter = scaleIn(),
exit = scaleOut() exit = scaleOut()
) { ) {

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.onboarding.messagenotifications package org.thoughtcrime.securesms.onboarding.messagenotifications
import android.app.Activity
import android.os.Bundle import android.os.Bundle
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -12,7 +13,8 @@ import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.home.startHomeActivity import org.thoughtcrime.securesms.home.startHomeActivity
import org.thoughtcrime.securesms.notifications.PushRegistry import org.thoughtcrime.securesms.notifications.PushRegistry
import org.thoughtcrime.securesms.onboarding.loading.LoadingActivity import org.thoughtcrime.securesms.onboarding.loading.LoadingActivity
import org.thoughtcrime.securesms.onboarding.loading.LoadingManager import org.thoughtcrime.securesms.onboarding.manager.LoadingManager
import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsActivity.Companion.EXTRA_PROFILE_NAME
import org.thoughtcrime.securesms.ui.setComposeContent import org.thoughtcrime.securesms.ui.setComposeContent
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
import org.thoughtcrime.securesms.util.start import org.thoughtcrime.securesms.util.start
@ -21,11 +23,22 @@ import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class MessageNotificationsActivity : BaseActionBarActivity() { class MessageNotificationsActivity : BaseActionBarActivity() {
companion object {
const val EXTRA_PROFILE_NAME = "EXTRA_PROFILE_NAME"
}
@Inject
internal lateinit var viewModelFactory: MessageNotificationsViewModel.AssistedFactory
@Inject lateinit var pushRegistry: PushRegistry @Inject lateinit var pushRegistry: PushRegistry
@Inject lateinit var prefs: TextSecurePreferences @Inject lateinit var prefs: TextSecurePreferences
@Inject lateinit var loadingManager: LoadingManager @Inject lateinit var loadingManager: LoadingManager
private val viewModel: MessageNotificationsViewModel by viewModels() val profileName by lazy { intent.getStringExtra(EXTRA_PROFILE_NAME) }
private val viewModel: MessageNotificationsViewModel by viewModels {
viewModelFactory.create(profileName)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -35,14 +48,28 @@ class MessageNotificationsActivity : BaseActionBarActivity() {
setComposeContent { MessageNotificationsScreen() } setComposeContent { MessageNotificationsScreen() }
} }
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (viewModel.onBackPressed()) return
@Suppress("DEPRECATION")
super.onBackPressed()
}
@Composable @Composable
private fun MessageNotificationsScreen() { private fun MessageNotificationsScreen() {
val state by viewModel.states.collectAsState() val uiState by viewModel.uiStates.collectAsState()
MessageNotificationsScreen(state, viewModel::setEnabled, ::register) MessageNotificationsScreen(
uiState,
setEnabled = viewModel::setEnabled,
onContinue = ::register,
quit = viewModel::quit,
dismissDialog = viewModel::dismissDialog
)
} }
private fun register() { private fun register() {
prefs.setPushEnabled(viewModel.states.value.pushEnabled) prefs.setPushEnabled(viewModel.uiStates.value.pushEnabled)
ApplicationContext.getInstance(this).startPollingIfNeeded() ApplicationContext.getInstance(this).startPollingIfNeeded()
pushRegistry.refresh(true) pushRegistry.refresh(true)
@ -52,3 +79,7 @@ class MessageNotificationsActivity : BaseActionBarActivity() {
} }
} }
} }
fun Activity.startMessageNotificationsActivity(profileName: String) {
start<MessageNotificationsActivity> { putExtra(EXTRA_PROFILE_NAME, profileName) }
}

@ -1,22 +1,83 @@
package org.thoughtcrime.securesms.onboarding.messagenotifications package org.thoughtcrime.securesms.onboarding.messagenotifications
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import javax.inject.Inject import kotlinx.coroutines.launch
import org.thoughtcrime.securesms.ApplicationContext
@HiltViewModel internal class MessageNotificationsViewModel(
internal class MessageNotificationsViewModel @Inject constructor(): ViewModel() { private val state: State,
private val _states = MutableStateFlow(MessageNotificationsState()) private val application: Application
val states = _states.asStateFlow() ): AndroidViewModel(application) {
private val _uiStates = MutableStateFlow(UiState())
val uiStates = _uiStates.asStateFlow()
fun setEnabled(enabled: Boolean) { fun setEnabled(enabled: Boolean) {
_states.update { MessageNotificationsState(pushEnabled = enabled) } _uiStates.update { UiState(pushEnabled = enabled) }
}
/**
* @return [true] if the back press was handled.
*/
fun onBackPressed(): Boolean = when (state) {
is State.CreateAccount -> false
is State.LoadAccount -> {
_uiStates.update { it.copy(showDialog = true) }
true
}
}
fun dismissDialog() {
_uiStates.update { it.copy(showDialog = false) }
}
fun quit() {
_uiStates.update { it.copy(clearData = true) }
viewModelScope.launch(Dispatchers.IO) {
ApplicationContext.getInstance(application).clearAllData()
}
} }
}
data class MessageNotificationsState(val pushEnabled: Boolean = true) { data class UiState(
val pushDisabled get() = !pushEnabled val pushEnabled: Boolean = true,
val showDialog: Boolean = false,
val clearData: Boolean = false
) {
val pushDisabled get() = !pushEnabled
}
sealed interface State {
class CreateAccount(val displayName: String): State
object LoadAccount: State
}
@dagger.assisted.AssistedFactory
interface AssistedFactory {
fun create(profileName: String?): Factory
}
@Suppress("UNCHECKED_CAST")
class Factory @AssistedInject constructor(
@Assisted private val profileName: String?,
private val application: Application
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return MessageNotificationsViewModel(
state = profileName?.let(State::CreateAccount) ?: State.LoadAccount,
application = application
) as T
}
}
} }

@ -13,10 +13,9 @@ import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.home.startHomeActivity import org.thoughtcrime.securesms.home.startHomeActivity
import org.thoughtcrime.securesms.onboarding.messagenotifications.MessageNotificationsActivity import org.thoughtcrime.securesms.onboarding.messagenotifications.startMessageNotificationsActivity
import org.thoughtcrime.securesms.ui.setComposeContent import org.thoughtcrime.securesms.ui.setComposeContent
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
import org.thoughtcrime.securesms.util.start
import javax.inject.Inject import javax.inject.Inject
private const val EXTRA_LOAD_FAILED = "extra_load_failed" private const val EXTRA_LOAD_FAILED = "extra_load_failed"
@ -41,11 +40,12 @@ class PickDisplayNameActivity : BaseActionBarActivity() {
setComposeContent { DisplayNameScreen(viewModel) } setComposeContent { DisplayNameScreen(viewModel) }
if (!loadFailed) prefs.setHasViewedSeed(false)
lifecycleScope.launch { lifecycleScope.launch {
viewModel.events.collect { viewModel.events.collect {
if (loadFailed) startHomeActivity() else start<MessageNotificationsActivity>() when (it) {
is Event.CreateAccount -> startMessageNotificationsActivity(it.profileName)
Event.LoadAccountComplete -> startHomeActivity()
}
} }
} }
} }

@ -49,6 +49,7 @@ internal class PickDisplayNameViewModel(
_states.update { it.copy(isTextErrorColor = false, error = null) } _states.update { it.copy(isTextErrorColor = false, error = null) }
prefs.setProfileName(displayName) prefs.setProfileName(displayName)
configFactory.user?.setName(displayName)
if (!loadFailed) { if (!loadFailed) {
// This is here to resolve a case where the app restarts before a user completes onboarding // This is here to resolve a case where the app restarts before a user completes onboarding
@ -70,7 +71,13 @@ internal class PickDisplayNameViewModel(
prefs.setRestorationTime(0) prefs.setRestorationTime(0)
} }
viewModelScope.launch { _events.emit(Event.DONE) } viewModelScope.launch {
if (loadFailed) {
_events.emit(Event.LoadAccountComplete)
} else {
_events.emit(Event.CreateAccount(displayName))
}
}
} }
} }
} }
@ -116,5 +123,6 @@ fun pickNewNameState() = State(
) )
sealed interface Event { sealed interface Event {
object DONE: Event class CreateAccount(val profileName: String): Event
object LoadAccountComplete: Event
} }

@ -110,7 +110,7 @@ class ClearAllDataDialog : DialogFragment() {
} catch (e: Exception) { } catch (e: Exception) {
Log.e("Loki", "Failed to force sync", e) Log.e("Loki", "Failed to force sync", e)
} }
ApplicationContext.getInstance(context).clearAllData(false) ApplicationContext.getInstance(context).clearAllData()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
dismiss() dismiss()
} }
@ -133,7 +133,7 @@ class ClearAllDataDialog : DialogFragment() {
} }
} else if (result.values.all { it }) { } else if (result.values.all { it }) {
// don't force sync because all the messages are deleted? // don't force sync because all the messages are deleted?
ApplicationContext.getInstance(context).clearAllData(false) ApplicationContext.getInstance(context).clearAllData()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
dismiss() dismiss()
} }

@ -18,6 +18,7 @@ import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -25,14 +26,9 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -44,11 +40,8 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.startWith
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import network.loki.messenger.BuildConfig import network.loki.messenger.BuildConfig
import network.loki.messenger.R import network.loki.messenger.R
import network.loki.messenger.databinding.ActivitySettingsBinding import network.loki.messenger.databinding.ActivitySettingsBinding
@ -420,7 +413,9 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
Cell { Cell {
Column { Column {
LargeItemButtonWithDrawable(R.string.activity_path_title, if (hasPaths) R.drawable.ic_status else R.drawable.ic_path_yellow) { show<PathActivity>() } Crossfade(if (hasPaths) R.drawable.ic_status else R.drawable.ic_path_yellow, label = "path") {
LargeItemButtonWithDrawable(R.string.activity_path_title, it) { show<PathActivity>() }
}
Divider() Divider()
LargeItemButton(R.string.activity_settings_privacy_button_title, R.drawable.ic_privacy_icon) { show<PrivacySettingsActivity>() } LargeItemButton(R.string.activity_settings_privacy_button_title, R.drawable.ic_privacy_icon) { show<PrivacySettingsActivity>() }
Divider() Divider()

@ -16,7 +16,9 @@ import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import network.loki.messenger.R import network.loki.messenger.R
@ -25,7 +27,9 @@ import org.thoughtcrime.securesms.ui.color.LocalColors
class DialogButtonModel( class DialogButtonModel(
val text: GetString, val text: GetString,
val contentDescription: GetString = text, val contentDescription: GetString = text,
val onClick: () -> Unit val color: Color = Color.Unspecified,
val dismissOnClick: Boolean = true,
val onClick: () -> Unit = {},
) )
@Composable @Composable
@ -33,6 +37,7 @@ fun AlertDialog(
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,
title: String? = null, title: String? = null,
text: String? = null, text: String? = null,
content: @Composable () -> Unit = {},
buttons: List<DialogButtonModel>? = null buttons: List<DialogButtonModel>? = null
) { ) {
androidx.compose.material.AlertDialog( androidx.compose.material.AlertDialog(
@ -76,6 +81,7 @@ fun AlertDialog(
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsItemSpacing) modifier = Modifier.padding(bottom = LocalDimensions.current.xxsItemSpacing)
) )
} }
content()
} }
buttons?.takeIf { it.isNotEmpty() }?.let { buttons?.takeIf { it.isNotEmpty() }?.let {
Row(Modifier.height(IntrinsicSize.Min)) { Row(Modifier.height(IntrinsicSize.Min)) {
@ -85,10 +91,11 @@ fun AlertDialog(
modifier = Modifier modifier = Modifier
.fillMaxHeight() .fillMaxHeight()
.contentDescription(it.contentDescription()) .contentDescription(it.contentDescription())
.weight(1f) .weight(1f),
color = it.color
) { ) {
it.onClick() it.onClick()
onDismissRequest() if (it.dismissOnClick) onDismissRequest()
} }
} }
} }
@ -100,7 +107,7 @@ fun AlertDialog(
} }
@Composable @Composable
fun DialogButton(text: String, modifier: Modifier, onClick: () -> Unit) { fun DialogButton(text: String, modifier: Modifier, color: Color = Color.Unspecified, onClick: () -> Unit) {
TextButton( TextButton(
modifier = modifier, modifier = modifier,
shape = RectangleShape, shape = RectangleShape,
@ -108,7 +115,7 @@ fun DialogButton(text: String, modifier: Modifier, onClick: () -> Unit) {
) { ) {
Text( Text(
text, text,
color = LocalColors.current.text, color = color.takeOrElse { LocalColors.current.text },
style = largeBold, style = largeBold,
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
modifier = Modifier.padding( modifier = Modifier.padding(

@ -26,7 +26,6 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.ButtonColors import androidx.compose.material.ButtonColors
import androidx.compose.material.Card import androidx.compose.material.Card
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
@ -69,6 +68,7 @@ import org.thoughtcrime.securesms.ui.color.LocalColors
import org.thoughtcrime.securesms.ui.color.divider import org.thoughtcrime.securesms.ui.color.divider
import org.thoughtcrime.securesms.ui.color.radioButtonColors import org.thoughtcrime.securesms.ui.color.radioButtonColors
import org.thoughtcrime.securesms.ui.color.transparentButtonColors import org.thoughtcrime.securesms.ui.color.transparentButtonColors
import org.thoughtcrime.securesms.ui.components.SmallCircularProgressIndicator
import kotlin.math.min import kotlin.math.min
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -453,11 +453,7 @@ fun LaunchedEffectAsync(block: suspend CoroutineScope.() -> Unit) {
@Composable @Composable
fun LoadingArcOr(loading: Boolean, content: @Composable () -> Unit) { fun LoadingArcOr(loading: Boolean, content: @Composable () -> Unit) {
AnimatedVisibility(loading) { AnimatedVisibility(loading) {
CircularProgressIndicator( SmallCircularProgressIndicator(color = LocalContentColor.current)
modifier = Modifier.size(20.dp),
color = LocalContentColor.current,
strokeWidth = 2.dp
)
} }
AnimatedVisibility(!loading) { AnimatedVisibility(!loading) {
content() content()

@ -0,0 +1,26 @@
package org.thoughtcrime.securesms.ui.components
import androidx.compose.foundation.layout.size
import androidx.compose.material.LocalContentColor
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun CircularProgressIndicator(color: Color = LocalContentColor.current) {
androidx.compose.material.CircularProgressIndicator(
modifier = Modifier.size(40.dp),
color = color,
strokeWidth = 2.dp
)
}
@Composable
fun SmallCircularProgressIndicator(color: Color = LocalContentColor.current) {
androidx.compose.material.CircularProgressIndicator(
modifier = Modifier.size(20.dp),
color = color,
strokeWidth = 2.dp
)
}

@ -1140,4 +1140,7 @@
<string name="AccessibilityId_copy_button">Copy button</string> <string name="AccessibilityId_copy_button">Copy button</string>
<string name="AccessibilityId_view_qr_code">View QR code</string> <string name="AccessibilityId_view_qr_code">View QR code</string>
<string name="AccessibilityId_qr_code">QR code</string> <string name="AccessibilityId_qr_code">QR code</string>
<string name="warning">Warning</string>
<string name="you_cannot_go_back_further_in_order_to_stop_loading_your_account_session_needs_to_quit">You cannot go back further. In order to stop loading your account, Session needs to quit.</string>
<string name="quit">Quit</string>
</resources> </resources>

Loading…
Cancel
Save