android: Saving prefs alert on exit with unsaved changes (#1508)
* android: Saving prefs alert on exit with unsaved changes * DIfferent implementation for AlertDialog with long buttons * Braces * Change * Alignment * Rename * small changes Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
887b374bfc
commit
ce11d58a76
@@ -63,8 +63,11 @@ fun ChatInfoView(
|
||||
setContactAlias(chat.chatInfo.apiId, it, chatModel)
|
||||
},
|
||||
openPreferences = {
|
||||
ModalManager.shared.showModal(true) {
|
||||
ContactPreferencesView(chatModel, chatModel.currentUser.value ?: return@showModal, contact.contactId)
|
||||
ModalManager.shared.showCustomModal { close ->
|
||||
val user = chatModel.currentUser.value
|
||||
if (user != null) {
|
||||
ContactPreferencesView(chatModel, user, contact.contactId, close)
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteContact = { deleteContactDialog(chat.chatInfo, chatModel, close) },
|
||||
|
||||
@@ -25,33 +25,45 @@ fun ContactPreferencesView(
|
||||
m: ChatModel,
|
||||
user: User,
|
||||
contactId: Long,
|
||||
close: () -> Unit,
|
||||
) {
|
||||
val contact = remember { derivedStateOf { (m.getContactChat(contactId)?.chatInfo as? ChatInfo.Direct)?.contact } }
|
||||
val ct = contact.value ?: return
|
||||
var featuresAllowed by remember(ct) { mutableStateOf(contactUserPrefsToFeaturesAllowed(ct.mergedPreferences)) }
|
||||
var currentFeaturesAllowed by remember(ct) { mutableStateOf(featuresAllowed) }
|
||||
ContactPreferencesLayout(
|
||||
featuresAllowed,
|
||||
currentFeaturesAllowed,
|
||||
user,
|
||||
ct,
|
||||
applyPrefs = { prefs ->
|
||||
featuresAllowed = prefs
|
||||
},
|
||||
reset = {
|
||||
featuresAllowed = currentFeaturesAllowed
|
||||
},
|
||||
savePrefs = {
|
||||
withApi {
|
||||
val prefs = contactFeaturesAllowedToPrefs(featuresAllowed)
|
||||
val toContact = m.controller.apiSetContactPrefs(ct.contactId, prefs)
|
||||
if (toContact != null) {
|
||||
m.updateContact(toContact)
|
||||
currentFeaturesAllowed = featuresAllowed
|
||||
}
|
||||
|
||||
fun savePrefs(afterSave: () -> Unit = {}) {
|
||||
withApi {
|
||||
val prefs = contactFeaturesAllowedToPrefs(featuresAllowed)
|
||||
val toContact = m.controller.apiSetContactPrefs(ct.contactId, prefs)
|
||||
if (toContact != null) {
|
||||
m.updateContact(toContact)
|
||||
currentFeaturesAllowed = featuresAllowed
|
||||
}
|
||||
afterSave()
|
||||
}
|
||||
}
|
||||
ModalView(
|
||||
close = {
|
||||
if (featuresAllowed == currentFeaturesAllowed) close()
|
||||
else showUnsavedChangesAlert({ savePrefs(close) }, close)
|
||||
},
|
||||
)
|
||||
background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight
|
||||
) {
|
||||
ContactPreferencesLayout(
|
||||
featuresAllowed,
|
||||
currentFeaturesAllowed,
|
||||
user,
|
||||
ct,
|
||||
applyPrefs = { prefs ->
|
||||
featuresAllowed = prefs
|
||||
},
|
||||
reset = {
|
||||
featuresAllowed = currentFeaturesAllowed
|
||||
},
|
||||
savePrefs = ::savePrefs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -139,3 +151,13 @@ private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(R.string.save_preferences_question),
|
||||
confirmText = generalGetString(R.string.save_and_notify_contact),
|
||||
dismissText = generalGetString(R.string.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = revert,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, ch
|
||||
selectedRole = selectedRole,
|
||||
allowModifyMembers = allowModifyMembers,
|
||||
openPreferences = {
|
||||
ModalManager.shared.showModal(true) {
|
||||
GroupPreferencesView(chatModel, groupInfo.id)
|
||||
ModalManager.shared.showCustomModal { close ->
|
||||
GroupPreferencesView(chatModel, groupInfo.id, close)
|
||||
}
|
||||
},
|
||||
inviteMembers = {
|
||||
|
||||
@@ -65,10 +65,11 @@ fun GroupChatInfoView(chatModel: ChatModel, close: () -> Unit) {
|
||||
ModalManager.shared.showCustomModal { close -> GroupProfileView(groupInfo, chatModel, close) }
|
||||
},
|
||||
openPreferences = {
|
||||
ModalManager.shared.showModal(true) {
|
||||
ModalManager.shared.showCustomModal { close ->
|
||||
GroupPreferencesView(
|
||||
chatModel,
|
||||
chat.id
|
||||
chat.id,
|
||||
close
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,41 +13,50 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.HighOrLowlight
|
||||
import chat.simplex.app.ui.theme.SimplexGreen
|
||||
import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
|
||||
@Composable
|
||||
fun GroupPreferencesView(m: ChatModel, chatId: String) {
|
||||
fun GroupPreferencesView(m: ChatModel, chatId: String, close: () -> Unit,) {
|
||||
val groupInfo = remember { derivedStateOf { (m.getChat(chatId)?.chatInfo as? ChatInfo.Group)?.groupInfo } }
|
||||
val gInfo = groupInfo.value ?: return
|
||||
var preferences by remember(gInfo) { mutableStateOf(gInfo.fullGroupPreferences) }
|
||||
var currentPreferences by remember(gInfo) { mutableStateOf(preferences) }
|
||||
GroupPreferencesLayout(
|
||||
preferences,
|
||||
currentPreferences,
|
||||
gInfo,
|
||||
applyPrefs = { prefs ->
|
||||
preferences = prefs
|
||||
},
|
||||
reset = {
|
||||
preferences = currentPreferences
|
||||
},
|
||||
savePrefs = {
|
||||
withApi {
|
||||
val gp = gInfo.groupProfile.copy(groupPreferences = preferences.toGroupPreferences())
|
||||
val gInfo = m.controller.apiUpdateGroup(gInfo.groupId, gp)
|
||||
if (gInfo != null) {
|
||||
m.updateGroup(gInfo)
|
||||
currentPreferences = preferences
|
||||
}
|
||||
|
||||
fun savePrefs(afterSave: () -> Unit = {}) {
|
||||
withApi {
|
||||
val gp = gInfo.groupProfile.copy(groupPreferences = preferences.toGroupPreferences())
|
||||
val gInfo = m.controller.apiUpdateGroup(gInfo.groupId, gp)
|
||||
if (gInfo != null) {
|
||||
m.updateGroup(gInfo)
|
||||
currentPreferences = preferences
|
||||
}
|
||||
afterSave()
|
||||
}
|
||||
}
|
||||
ModalView(
|
||||
close = {
|
||||
if (preferences == currentPreferences) close()
|
||||
else showUnsavedChangesAlert({ savePrefs(close) }, close)
|
||||
},
|
||||
)
|
||||
background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight
|
||||
) {
|
||||
GroupPreferencesLayout(
|
||||
preferences,
|
||||
currentPreferences,
|
||||
gInfo,
|
||||
applyPrefs = { prefs ->
|
||||
preferences = prefs
|
||||
},
|
||||
reset = {
|
||||
preferences = currentPreferences
|
||||
},
|
||||
savePrefs = ::savePrefs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -130,3 +139,13 @@ private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(R.string.save_preferences_question),
|
||||
confirmText = generalGetString(R.string.save_and_notify_group_members),
|
||||
dismissText = generalGetString(R.string.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = revert,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.unit.*
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import chat.simplex.app.R
|
||||
import chat.simplex.app.TAG
|
||||
@@ -93,6 +94,41 @@ class AlertManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun showAlertDialogStacked(
|
||||
title: String,
|
||||
text: String? = null,
|
||||
confirmText: String = generalGetString(R.string.ok),
|
||||
onConfirm: (() -> Unit)? = null,
|
||||
dismissText: String = generalGetString(R.string.cancel_verb),
|
||||
onDismiss: (() -> Unit)? = null,
|
||||
onDismissRequest: (() -> Unit)? = null,
|
||||
destructive: Boolean = false
|
||||
) {
|
||||
val alertText: (@Composable () -> Unit)? = if (text == null) null else { -> Text(text) }
|
||||
showAlert {
|
||||
AlertDialog(
|
||||
onDismissRequest = { onDismissRequest?.invoke(); hideAlert() },
|
||||
title = { Text(title) },
|
||||
text = alertText,
|
||||
buttons = {
|
||||
Column(
|
||||
Modifier.fillMaxWidth().padding(horizontal = 8.dp).padding(top = 16.dp, bottom = 2.dp),
|
||||
horizontalAlignment = Alignment.End
|
||||
) {
|
||||
TextButton(onClick = {
|
||||
onDismiss?.invoke()
|
||||
hideAlert()
|
||||
}) { Text(dismissText) }
|
||||
TextButton(onClick = {
|
||||
onConfirm?.invoke()
|
||||
hideAlert()
|
||||
}) { Text(confirmText, color = if (destructive) MaterialTheme.colors.error else Color.Unspecified) }
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun showAlertMsg(
|
||||
title: String, text: String? = null,
|
||||
confirmText: String = generalGetString(R.string.ok), onConfirm: (() -> Unit)? = null
|
||||
@@ -128,4 +164,4 @@ class AlertManager {
|
||||
companion object {
|
||||
val shared = AlertManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,33 +19,40 @@ import chat.simplex.app.ui.theme.*
|
||||
import chat.simplex.app.views.helpers.*
|
||||
|
||||
@Composable
|
||||
fun PreferencesView(m: ChatModel, user: User) {
|
||||
fun PreferencesView(m: ChatModel, user: User, close: () -> Unit,) {
|
||||
var preferences by remember { mutableStateOf(user.fullPreferences) }
|
||||
var currentPreferences by remember { mutableStateOf(preferences) }
|
||||
PreferencesLayout(
|
||||
preferences,
|
||||
currentPreferences,
|
||||
applyPrefs = { prefs ->
|
||||
preferences = prefs
|
||||
},
|
||||
reset = {
|
||||
preferences = currentPreferences
|
||||
},
|
||||
savePrefs = {
|
||||
withApi {
|
||||
val newProfile = user.profile.toProfile().copy(preferences = preferences.toPreferences())
|
||||
val updatedProfile = m.controller.apiUpdateProfile(newProfile)
|
||||
if (updatedProfile != null) {
|
||||
val updatedUser = user.copy(
|
||||
profile = updatedProfile.toLocalProfile(user.profile.profileId),
|
||||
fullPreferences = preferences
|
||||
)
|
||||
currentPreferences = preferences
|
||||
m.currentUser.value = updatedUser
|
||||
}
|
||||
|
||||
fun savePrefs(afterSave: () -> Unit = {}) {
|
||||
withApi {
|
||||
val newProfile = user.profile.toProfile().copy(preferences = preferences.toPreferences())
|
||||
val updatedProfile = m.controller.apiUpdateProfile(newProfile)
|
||||
if (updatedProfile != null) {
|
||||
val updatedUser = user.copy(
|
||||
profile = updatedProfile.toLocalProfile(user.profile.profileId),
|
||||
fullPreferences = preferences
|
||||
)
|
||||
currentPreferences = preferences
|
||||
m.currentUser.value = updatedUser
|
||||
}
|
||||
afterSave()
|
||||
}
|
||||
}
|
||||
ModalView(
|
||||
close = {
|
||||
if (preferences == currentPreferences) close()
|
||||
else showUnsavedChangesAlert({ savePrefs(close) }, close)
|
||||
},
|
||||
)
|
||||
background = if (isInDarkTheme()) MaterialTheme.colors.background else SettingsBackgroundLight
|
||||
) {
|
||||
PreferencesLayout(
|
||||
preferences,
|
||||
currentPreferences,
|
||||
applyPrefs = { preferences = it },
|
||||
reset = { preferences = currentPreferences },
|
||||
savePrefs = ::savePrefs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -107,3 +114,13 @@ private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Bool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialogStacked(
|
||||
title = generalGetString(R.string.save_preferences_question),
|
||||
confirmText = generalGetString(R.string.save_and_notify_contacts),
|
||||
dismissText = generalGetString(R.string.exit_without_saving),
|
||||
onConfirm = save,
|
||||
onDismiss = revert,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ fun SettingsLayout(
|
||||
SectionDivider()
|
||||
SettingsActionItem(Icons.Outlined.QrCode, stringResource(R.string.your_simplex_contact_address), showModal { CreateLinkView(it, CreateLinkTab.LONG_TERM) }, disabled = stopped)
|
||||
SectionDivider()
|
||||
ChatPreferencesItem(showSettingsModal)
|
||||
ChatPreferencesItem(showCustomModal)
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
@@ -239,14 +239,14 @@ fun MaintainIncognitoState(chatModel: ChatModel) {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable fun ChatPreferencesItem(showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||
@Composable fun ChatPreferencesItem(showCustomModal: ((@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit))) {
|
||||
SettingsActionItem(
|
||||
Icons.Outlined.ToggleOn,
|
||||
stringResource(R.string.chat_preferences),
|
||||
click = {
|
||||
withApi {
|
||||
showSettingsModal {
|
||||
PreferencesView(it, it.currentUser.value ?: return@showSettingsModal)
|
||||
showCustomModal { m, close ->
|
||||
PreferencesView(m, m.currentUser.value ?: return@showCustomModal, close)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,9 +475,11 @@
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Ihr Profil wird auf Ihrem Gerät gespeichert und nur mit Ihren Kontakten geteilt.\n\n<xliff:g id="appName">SimpleX</xliff:g>-Server können Ihr Profil nicht sehen.</string>
|
||||
<string name="edit_image">Bild bearbeiten</string>
|
||||
<string name="delete_image">Bild löschen</string>
|
||||
<string name="save_and_notify_contact">Speichern (und Kontakt benachrichtigen)</string>
|
||||
<string name="save_and_notify_contacts">Speichern (und Kontakte benachrichtigen)</string>
|
||||
<string name="save_and_notify_group_members">Speichern (und Gruppenmitglieder benachrichtigen)</string>
|
||||
<string name="save_preferences_question">Präferenzen speichern?</string>
|
||||
<string name="save_and_notify_contact">Speichern und Kontakt benachrichtigen</string>
|
||||
<string name="save_and_notify_contacts">Speichern und Kontakte benachrichtigen</string>
|
||||
<string name="save_and_notify_group_members">Speichern und Gruppenmitglieder benachrichtigen</string>
|
||||
<string name="exit_without_saving">Beenden ohne Speichern</string>
|
||||
|
||||
<!-- Welcome Prompts - WelcomeView.kt -->
|
||||
<string name="you_control_your_chat">Sie haben volle Kontrolle über Ihren Chat!</string>
|
||||
|
||||
@@ -472,9 +472,11 @@
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Ваш профиль хранится на вашем устройстве и отправляется только вашим контактам.\n\n<xliff:g id="appName">SimpleX</xliff:g> серверы не могут получить доступ к вашему профилю.</string>
|
||||
<string name="edit_image">Поменять аватар</string>
|
||||
<string name="delete_image">Удалить аватар</string>
|
||||
<string name="save_and_notify_contact">Сохранить (и уведомить контакт)</string>
|
||||
<string name="save_and_notify_contacts">Сохранить (и послать обновление контактам)</string>
|
||||
<string name="save_and_notify_group_members">Сохранить (и уведомить членов группы)</string>
|
||||
<string name="save_preferences_question">Сохранить предпочтения?</string>
|
||||
<string name="save_and_notify_contact">Сохранить и уведомить контакт</string>
|
||||
<string name="save_and_notify_contacts">Сохранить и уведомить контакты</string>
|
||||
<string name="save_and_notify_group_members">Сохранить и уведомить членов группы</string>
|
||||
<string name="exit_without_saving">Выйти без сохранения</string>
|
||||
|
||||
<!-- Welcome Prompts - WelcomeView.kt -->
|
||||
<string name="you_control_your_chat">Вы котролируете ваш чат!</string>
|
||||
|
||||
@@ -475,9 +475,11 @@
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Your profile is stored on your device and shared only with your contacts.\n\n<xliff:g id="appName">SimpleX</xliff:g> servers cannot see your profile.</string>
|
||||
<string name="edit_image">Edit image</string>
|
||||
<string name="delete_image">Delete image</string>
|
||||
<string name="save_and_notify_contact">Save (and notify contact)</string>
|
||||
<string name="save_and_notify_contacts">Save (and notify contacts)</string>
|
||||
<string name="save_and_notify_group_members">Save (and notify group members)</string>
|
||||
<string name="save_preferences_question">Save preferences?</string>
|
||||
<string name="save_and_notify_contact">Save and notify contact</string>
|
||||
<string name="save_and_notify_contacts">Save and notify contacts</string>
|
||||
<string name="save_and_notify_group_members">Save and notify group members</string>
|
||||
<string name="exit_without_saving">Exit without saving</string>
|
||||
|
||||
<!-- Welcome Prompts - WelcomeView.kt -->
|
||||
<string name="you_control_your_chat">You control your chat!</string>
|
||||
|
||||
Reference in New Issue
Block a user