mobile: settings for auto-accepting images, link previews, spinner for link previews; privacy settings (#708)

* ios: settings for auto-accepting images, link previews, spinner for link previews

* android: settings for auto-accepting images, link previews, spinner for link previews, privacy settings

* update translation

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>

* translation

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>

* translation

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>

Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>
This commit is contained in:
Evgeny Poberezkin
2022-05-30 08:59:04 +01:00
committed by GitHub
parent 7c1d573a17
commit 29e2c00811
28 changed files with 508 additions and 213 deletions
@@ -78,6 +78,8 @@ class AppPreferences(val context: Context) {
)
val performLA = mkBoolPreference(SHARED_PREFS_PERFORM_LA, false)
val laNoticeShown = mkBoolPreference(SHARED_PREFS_LA_NOTICE_SHOWN, false)
val privacyAcceptImages = mkBoolPreference(SHARED_PREFS_PRIVACY_ACCEPT_IMAGES, true)
val privacyLinkPreviews = mkBoolPreference(SHARED_PREFS_PRIVACY_LINK_PREVIEWS, true)
private fun mkIntPreference(prefName: String, default: Int) =
Preference(
@@ -107,6 +109,8 @@ class AppPreferences(val context: Context) {
private const val SHARED_PREFS_WEBRTC_CALLS_ON_LOCK_SCREEN = "CallsOnLockScreen"
private const val SHARED_PREFS_PERFORM_LA = "PerformLA"
private const val SHARED_PREFS_LA_NOTICE_SHOWN = "LANoticeShown"
private const val SHARED_PREFS_PRIVACY_ACCEPT_IMAGES = "PrivacyAcceptImages"
private const val SHARED_PREFS_PRIVACY_LINK_PREVIEWS = "PrivacyLinkPreviews"
}
}
@@ -510,13 +514,8 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
val cItem = r.chatItem.chatItem
chatModel.addChatItem(cInfo, cItem)
val file = cItem.file
if (cItem.content.msgContent is MsgContent.MCImage && file != null && file.fileSize <= MAX_IMAGE_SIZE) {
withApi {
val chatItem = apiReceiveFile(file.fileId)
if (chatItem != null) {
chatItemSimpleUpdate(chatItem)
}
}
if (cItem.content.msgContent is MsgContent.MCImage && file != null && file.fileSize <= MAX_IMAGE_SIZE && appPrefs.privacyAcceptImages.get()) {
withApi { receiveFile(file.fileId) }
}
if (!cItem.isCall && (!isAppOnForeground(appContext) || chatModel.chatId.value != cInfo.id)) {
ntfManager.notifyMessageReceived(cInfo, cItem)
@@ -615,6 +614,13 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
}
}
suspend fun receiveFile(fileId: Long) {
val chatItem = apiReceiveFile(fileId)
if (chatItem != null) {
chatItemSimpleUpdate(chatItem)
}
}
private fun chatItemSimpleUpdate(aChatItem: AChatItem) {
val cInfo = aChatItem.chatInfo
val cItem = aChatItem.chatItem
@@ -26,7 +26,7 @@ import kotlinx.coroutines.launch
@Composable
fun TerminalView(chatModel: ChatModel, close: () -> Unit) {
val composeState = remember { mutableStateOf(ComposeState()) }
val composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) }
BackHandler(onBack = close)
TerminalLayout(
chatModel.terminalItems,
@@ -35,7 +35,7 @@ fun TerminalView(chatModel: ChatModel, close: () -> Unit) {
withApi {
// show "in progress"
chatModel.controller.sendCmd(CC.Console(composeState.value.message))
composeState.value = ComposeState()
composeState.value = ComposeState(useLinkPreviews = false)
// hide "in progress"
}
},
@@ -120,7 +120,7 @@ fun PreviewTerminalLayout() {
SimpleXTheme {
TerminalLayout(
terminalItems = TerminalItem.sampleData,
composeState = remember { mutableStateOf(ComposeState()) },
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = false)) },
sendCommand = {},
close = {}
)
@@ -44,7 +44,8 @@ import kotlinx.datetime.Clock
fun ChatView(chatModel: ChatModel) {
val chat: Chat? = chatModel.chats.firstOrNull { chat -> chat.chatInfo.id == chatModel.chatId.value }
val user = chatModel.currentUser.value
val composeState = remember { mutableStateOf(ComposeState()) }
val useLinkPreviews = chatModel.controller.appPrefs.privacyLinkPreviews.get()
val composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = useLinkPreviews)) }
val attachmentOption = remember { mutableStateOf<AttachmentOption?>(null) }
val attachmentBottomSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
@@ -83,6 +84,7 @@ fun ChatView(chatModel: ChatModel) {
scope,
attachmentBottomSheetState,
chatModel.chatItems,
useLinkPreviews = useLinkPreviews,
back = { chatModel.chatId.value = null },
info = { ModalManager.shared.showCustomModal { close -> ChatInfoView(chatModel, close) } },
openDirectChat = { contactId ->
@@ -104,14 +106,7 @@ fun ChatView(chatModel: ChatModel) {
}
},
receiveFile = { fileId ->
withApi {
val chatItem = chatModel.controller.apiReceiveFile(fileId)
if (chatItem != null) {
val cInfo = chatItem.chatInfo
val cItem = chatItem.chatItem
chatModel.upsertChatItem(cInfo, cItem)
}
}
withApi { chatModel.controller.receiveFile(fileId) }
},
startCall = { media ->
val cInfo = chat.chatInfo
@@ -143,6 +138,7 @@ fun ChatLayout(
scope: CoroutineScope,
attachmentBottomSheetState: ModalBottomSheetState,
chatItems: List<ChatItem>,
useLinkPreviews: Boolean,
back: () -> Unit,
info: () -> Unit,
openDirectChat: (Long) -> Unit,
@@ -175,7 +171,7 @@ fun ChatLayout(
modifier = Modifier.navigationBarsWithImePadding()
) { contentPadding ->
Box(Modifier.padding(contentPadding)) {
ChatItemsList(user, chat, composeState, chatItems, openDirectChat, deleteMessage, receiveFile, acceptCall)
ChatItemsList(user, chat, composeState, chatItems, useLinkPreviews, openDirectChat, deleteMessage, receiveFile, acceptCall)
}
}
}
@@ -261,6 +257,7 @@ fun ChatItemsList(
chat: Chat,
composeState: MutableState<ComposeState>,
chatItems: List<ChatItem>,
useLinkPreviews: Boolean,
openDirectChat: (Long) -> Unit,
deleteMessage: (Long, CIDeleteMode) -> Unit,
receiveFile: (Long) -> Unit,
@@ -302,11 +299,11 @@ fun ChatItemsList(
} else {
Spacer(Modifier.size(42.dp))
}
ChatItemView(user, chat.chatInfo, cItem, composeState, cxt, uriHandler, showMember = showMember, deleteMessage = deleteMessage, receiveFile = receiveFile, acceptCall = acceptCall)
ChatItemView(user, chat.chatInfo, cItem, composeState, cxt, uriHandler, showMember = showMember, useLinkPreviews = useLinkPreviews, deleteMessage = deleteMessage, receiveFile = receiveFile, acceptCall = acceptCall)
}
} else {
Box(Modifier.padding(start = 86.dp, end = 12.dp)) {
ChatItemView(user, chat.chatInfo, cItem, composeState, cxt, uriHandler, deleteMessage = deleteMessage, receiveFile = receiveFile, acceptCall = acceptCall)
ChatItemView(user, chat.chatInfo, cItem, composeState, cxt, uriHandler, useLinkPreviews = useLinkPreviews, deleteMessage = deleteMessage, receiveFile = receiveFile, acceptCall = acceptCall)
}
}
} else { // direct message
@@ -317,7 +314,7 @@ fun ChatItemsList(
end = if (sent) 12.dp else 76.dp,
)
) {
ChatItemView(user, chat.chatInfo, cItem, composeState, cxt, uriHandler, deleteMessage = deleteMessage, receiveFile = receiveFile, acceptCall = acceptCall)
ChatItemView(user, chat.chatInfo, cItem, composeState, cxt, uriHandler, useLinkPreviews = useLinkPreviews, deleteMessage = deleteMessage, receiveFile = receiveFile, acceptCall = acceptCall)
}
}
}
@@ -375,12 +372,13 @@ fun PreviewChatLayout() {
chatItems = chatItems,
chatStats = Chat.ChatStats()
),
composeState = remember { mutableStateOf(ComposeState()) },
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = true)) },
composeView = {},
attachmentOption = remember { mutableStateOf<AttachmentOption?>(null) },
scope = rememberCoroutineScope(),
attachmentBottomSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden),
chatItems = chatItems,
useLinkPreviews = true,
back = {},
info = {},
openDirectChat = {},
@@ -421,12 +419,13 @@ fun PreviewGroupChatLayout() {
chatItems = chatItems,
chatStats = Chat.ChatStats()
),
composeState = remember { mutableStateOf(ComposeState()) },
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = true)) },
composeView = {},
attachmentOption = remember { mutableStateOf<AttachmentOption?>(null) },
scope = rememberCoroutineScope(),
attachmentBottomSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden),
chatItems = chatItems,
useLinkPreviews = true,
back = {},
info = {},
openDirectChat = {},
@@ -45,7 +45,7 @@ import java.io.File
sealed class ComposePreview {
object NoPreview: ComposePreview()
class CLinkPreview(val linkPreview: LinkPreview): ComposePreview()
class CLinkPreview(val linkPreview: LinkPreview?): ComposePreview()
class ImagePreview(val image: String): ComposePreview()
class FilePreview(val fileName: String): ComposePreview()
}
@@ -60,12 +60,14 @@ data class ComposeState(
val message: String = "",
val preview: ComposePreview = ComposePreview.NoPreview,
val contextItem: ComposeContextItem = ComposeContextItem.NoContextItem,
val inProgress: Boolean = false
val inProgress: Boolean = false,
val useLinkPreviews: Boolean
) {
constructor(editingItem: ChatItem): this(
constructor(editingItem: ChatItem, useLinkPreviews: Boolean): this (
editingItem.content.text,
chatItemPreview(editingItem),
ComposeContextItem.EditingItem(editingItem)
ComposeContextItem.EditingItem(editingItem),
useLinkPreviews = useLinkPreviews
)
val editing: Boolean
@@ -88,7 +90,7 @@ data class ComposeState(
when (preview) {
is ComposePreview.ImagePreview -> false
is ComposePreview.FilePreview -> false
else -> true
else -> useLinkPreviews
}
val linkPreview: LinkPreview?
get() =
@@ -124,6 +126,7 @@ fun ComposeView(
val prevLinkUrl = remember { mutableStateOf<String?>(null) }
val pendingLinkUrl = remember { mutableStateOf<String?>(null) }
val cancelledLinks = remember { mutableSetOf<String>() }
val useLinkPreviews = chatModel.controller.appPrefs.privacyLinkPreviews.get()
val smallFont = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground)
val textStyle = remember { mutableStateOf(smallFont) }
// attachments
@@ -239,6 +242,7 @@ fun ComposeView(
fun loadLinkPreview(url: String, wait: Long? = null) {
if (pendingLinkUrl.value == url) {
composeState.value = composeState.value.copy(preview = ComposePreview.CLinkPreview(null))
withApi {
if (wait != null) delay(wait)
val lp = getLinkPreview(url)
@@ -277,7 +281,7 @@ fun ComposeView(
is ComposePreview.CLinkPreview -> {
val url = parseMessage(cs.message)
val lp = composePreview.linkPreview
if (url == lp.uri) {
if (lp != null && url == lp.uri) {
MsgContent.MCLink(cs.message, preview = lp)
} else {
MsgContent.MCText(cs.message)
@@ -299,7 +303,7 @@ fun ComposeView(
}
fun clearState() {
composeState.value = ComposeState()
composeState.value = ComposeState(useLinkPreviews = useLinkPreviews)
textStyle.value = smallFont
chosenImage.value = null
chosenFile.value = null
@@ -397,6 +401,7 @@ fun ComposeView(
if (uri != null) {
cancelledLinks.add(uri)
}
pendingLinkUrl.value = null
composeState.value = composeState.value.copy(preview = ComposePreview.NoPreview)
}
@@ -111,7 +111,7 @@ fun PreviewSendMsgView() {
val textStyle = remember { mutableStateOf(smallFont) }
SimpleXTheme {
SendMsgView(
composeState = remember { mutableStateOf(ComposeState()) },
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = true)) },
sendMessage = {},
onMessageChange = { _ -> },
textStyle = textStyle
@@ -129,7 +129,7 @@ fun PreviewSendMsgView() {
fun PreviewSendMsgViewEditing() {
val smallFont = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground)
val textStyle = remember { mutableStateOf(smallFont) }
val composeStateEditing = ComposeState(editingItem = ChatItem.getSampleData())
val composeStateEditing = ComposeState(editingItem = ChatItem.getSampleData(), useLinkPreviews = true)
SimpleXTheme {
SendMsgView(
composeState = remember { mutableStateOf(composeStateEditing) },
@@ -150,7 +150,7 @@ fun PreviewSendMsgViewEditing() {
fun PreviewSendMsgViewInProgress() {
val smallFont = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground)
val textStyle = remember { mutableStateOf(smallFont) }
val composeStateInProgress = ComposeState(preview = ComposePreview.FilePreview("test.txt"), inProgress = true)
val composeStateInProgress = ComposeState(preview = ComposePreview.FilePreview("test.txt"), inProgress = true, useLinkPreviews = true)
SimpleXTheme {
SendMsgView(
composeState = remember { mutableStateOf(composeStateInProgress) },
@@ -26,7 +26,8 @@ import chat.simplex.app.views.helpers.*
fun CIImageView(
image: String,
file: CIFile?,
showMenu: MutableState<Boolean>
showMenu: MutableState<Boolean>,
receiveFile: (Long) -> Unit
) {
@Composable
fun loadingIndicator() {
@@ -98,11 +99,21 @@ fun CIImageView(
})
} else {
imageView(base64ToBitmap(image), onClick = {
if (file != null && file.fileStatus == CIFileStatus.RcvAccepted)
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_image),
generalGetString(R.string.image_will_be_received_when_contact_is_online)
)
if (file != null) {
when (file.fileStatus) {
CIFileStatus.RcvInvitation ->
receiveFile(file.fileId)
CIFileStatus.RcvAccepted ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_image),
generalGetString(R.string.image_will_be_received_when_contact_is_online)
)
CIFileStatus.RcvTransfer -> {} // ?
CIFileStatus.RcvComplete -> {} // ?
CIFileStatus.RcvCancelled -> {} // TODO
else -> {}
}
}
})
}
loadingIndicator()
@@ -36,6 +36,7 @@ fun ChatItemView(
cxt: Context,
uriHandler: UriHandler? = null,
showMember: Boolean = false,
useLinkPreviews: Boolean,
deleteMessage: (Long, CIDeleteMode) -> Unit,
receiveFile: (Long) -> Unit,
acceptCall: (Contact) -> Unit
@@ -69,7 +70,7 @@ fun ChatItemView(
) {
ItemAction(stringResource(R.string.reply_verb), Icons.Outlined.Reply, onClick = {
if (composeState.value.editing) {
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem))
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
} else {
composeState.value = composeState.value.copy(contextItem = ComposeContextItem.QuotedItem(cItem))
}
@@ -98,7 +99,7 @@ fun ChatItemView(
}
if (cItem.meta.editable) {
ItemAction(stringResource(R.string.edit_verb), Icons.Filled.Edit, onClick = {
composeState.value = ComposeState(editingItem = cItem)
composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews)
showMenu.value = false
})
}
@@ -203,7 +204,8 @@ fun PreviewChatItemView() {
ChatItem.getSampleData(
1, CIDirection.DirectSnd(), Clock.System.now(), "hello"
),
composeState = remember { mutableStateOf(ComposeState()) },
useLinkPreviews = true,
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = true)) },
cxt = LocalContext.current,
deleteMessage = { _, _ -> },
receiveFile = {},
@@ -220,7 +222,8 @@ fun PreviewChatItemViewDeletedContent() {
User.sampleData,
ChatInfo.Direct.sampleData,
ChatItem.getDeletedContentSampleData(),
composeState = remember { mutableStateOf(ComposeState()) },
useLinkPreviews = true,
composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = true)) },
cxt = LocalContext.current,
deleteMessage = { _, _ -> },
receiveFile = {},
@@ -121,7 +121,7 @@ fun FramedItemView(
Column(Modifier.fillMaxWidth()) {
when (val mc = ci.content.msgContent) {
is MsgContent.MCImage -> {
CIImageView(image = mc.image, file = ci.file, showMenu)
CIImageView(image = mc.image, file = ci.file, showMenu, receiveFile)
if (mc.text == "") {
metaColor = Color.White
} else {
@@ -11,6 +11,7 @@ import androidx.compose.material.icons.outlined.Close
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
@@ -66,23 +67,36 @@ suspend fun getLinkPreview(url: String): LinkPreview? {
@Composable
fun ComposeLinkView(linkPreview: LinkPreview, cancelPreview: () -> Unit) {
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit) {
Row(
Modifier.fillMaxWidth().padding(top = 8.dp).background(SentColorLight),
verticalAlignment = Alignment.CenterVertically
) {
val imageBitmap = base64ToBitmap(linkPreview.image).asImageBitmap()
Image(
imageBitmap,
stringResource(R.string.image_descr_link_preview),
modifier = Modifier.width(80.dp).height(60.dp).padding(end = 8.dp)
)
Column(Modifier.fillMaxWidth().weight(1F)) {
Text(linkPreview.title, maxLines = 1, overflow = TextOverflow.Ellipsis)
Text(
linkPreview.uri, maxLines = 1, overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.body2
if (linkPreview == null) {
Box(
Modifier.fillMaxWidth().weight(1f).height(60.dp).padding(start = 16.dp),
contentAlignment = Alignment.CenterStart
) {
CircularProgressIndicator(
Modifier.size(16.dp),
color = HighOrLowlight,
strokeWidth = 2.dp
)
}
} else {
val imageBitmap = base64ToBitmap(linkPreview.image).asImageBitmap()
Image(
imageBitmap,
stringResource(R.string.image_descr_link_preview),
modifier = Modifier.width(80.dp).height(60.dp).padding(end = 8.dp)
)
Column(Modifier.fillMaxWidth().weight(1F)) {
Text(linkPreview.title, maxLines = 1, overflow = TextOverflow.Ellipsis)
Text(
linkPreview.uri, maxLines = 1, overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.body2
)
}
}
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
Icon(
@@ -139,4 +153,12 @@ fun PreviewComposeLinkView() {
SimpleXTheme {
ComposeLinkView(LinkPreview.sampleData) { -> }
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewComposeLinkViewLoading() {
SimpleXTheme {
ComposeLinkView(null) { -> }
}
}
@@ -34,7 +34,7 @@ fun CallSettingsLayout(
) {
val lockCallState = remember { mutableStateOf(callOnLockScreen.get()) }
Text(
stringResource(R.string.call_settings),
stringResource(R.string.your_calls),
Modifier.padding(bottom = 24.dp),
style = MaterialTheme.typography.h1
)
@@ -71,6 +71,7 @@ fun SharedPreferenceToggle(
checkedThumbColor = MaterialTheme.colors.primary,
uncheckedThumbColor = HighOrLowlight
),
modifier = Modifier.padding(end = 6.dp)
)
}
}
@@ -0,0 +1,65 @@
package chat.simplex.app.views.usersettings
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.HighOrLowlight
@Composable
fun PrivacySettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) {
@Composable fun divider() = Divider(Modifier.padding(horizontal = 8.dp))
Column(
Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
stringResource(R.string.your_privacy),
style = MaterialTheme.typography.h1,
modifier = Modifier.padding(start = 8.dp, bottom = 24.dp)
)
ChatLockSection(chatModel.performLA, setPerformLA)
Spacer(Modifier.height(24.dp))
AutoAcceptImagesSection(chatModel.controller.appPrefs.privacyAcceptImages)
divider()
LinkPreviewsSection(chatModel.controller.appPrefs.privacyLinkPreviews)
divider()
}
}
@Composable private fun AutoAcceptImagesSection(prefAcceptImages: Preference<Boolean>) {
SettingsSectionView() {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
Icons.Outlined.Image,
contentDescription = stringResource(R.string.auto_accept_images),
tint = HighOrLowlight,
)
Spacer(Modifier.padding(horizontal = 4.dp))
SharedPreferenceToggle(stringResource(R.string.auto_accept_images), prefAcceptImages)
}
}
}
@Composable private fun LinkPreviewsSection(prefLinkPreviews: Preference<Boolean>) {
SettingsSectionView() {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
Icons.Outlined.TravelExplore,
contentDescription = stringResource(R.string.send_link_previews),
tint = HighOrLowlight,
)
Spacer(Modifier.padding(horizontal = 4.dp))
SharedPreferenceToggle(stringResource(R.string.send_link_previews), prefLinkPreviews)
}
}
}
@@ -47,7 +47,6 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) {
profile = user.profile,
runServiceInBackground = chatModel.runServiceInBackground,
setRunServiceInBackground = ::setRunServiceInBackground,
performLA = chatModel.performLA,
setPerformLA = setPerformLA,
showModal = { modalView -> { ModalManager.shared.showModal { modalView(chatModel) } } },
showCustomModal = { modalView -> { ModalManager.shared.showCustomModal { close -> modalView(chatModel, close) } } },
@@ -65,7 +64,6 @@ fun SettingsLayout(
profile: Profile,
runServiceInBackground: MutableState<Boolean>,
setRunServiceInBackground: (Boolean) -> Unit,
performLA: MutableState<Boolean>,
setPerformLA: (Boolean) -> Unit,
showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
showCustomModal: (@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit),
@@ -103,7 +101,7 @@ fun SettingsLayout(
CallSettingsSection(showModal)
divider()
ChatLockSection(performLA, setPerformLA)
PrivacySettingsSection(showModal, setPerformLA)
divider()
PrivateNotificationsSection(runServiceInBackground, setRunServiceInBackground)
divider()
@@ -154,6 +152,18 @@ fun SettingsLayout(
}
}
@Composable private fun PrivacySettingsSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), setPerformLA: (Boolean) -> Unit) {
SettingsSectionView(showModal { PrivacySettingsView(it, setPerformLA) }) {
Icon(
Icons.Outlined.Lock,
contentDescription = stringResource(R.string.privacy_and_security),
tint = HighOrLowlight,
)
Spacer(Modifier.padding(horizontal = 4.dp))
Text(stringResource(R.string.privacy_and_security))
}
}
@Composable private fun HelpViewSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
SettingsSectionView(showModal { HelpView(it) }) {
Icon(
@@ -258,13 +268,13 @@ fun SettingsLayout(
checkedThumbColor = MaterialTheme.colors.primary,
uncheckedThumbColor = HighOrLowlight
),
modifier = Modifier.padding(end = 8.dp)
modifier = Modifier.padding(end = 6.dp)
)
}
}
}
@Composable private fun ChatLockSection(performLA: MutableState<Boolean>, setPerformLA: (Boolean) -> Unit) {
@Composable fun ChatLockSection(performLA: MutableState<Boolean>, setPerformLA: (Boolean) -> Unit) {
SettingsSectionView() {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
@@ -286,7 +296,7 @@ fun SettingsLayout(
checkedThumbColor = MaterialTheme.colors.primary,
uncheckedThumbColor = HighOrLowlight
),
modifier = Modifier.padding(end = 8.dp)
modifier = Modifier.padding(end = 6.dp)
)
}
}
@@ -362,7 +372,6 @@ fun PreviewSettingsLayout() {
profile = Profile.sampleData,
runServiceInBackground = remember { mutableStateOf(true) },
setRunServiceInBackground = {},
performLA = remember { mutableStateOf(false) },
setPerformLA = {},
showModal = { {} },
showCustomModal = { {} },
@@ -168,7 +168,7 @@
<string name="toast_permission_denied">Разрешение не получено!</string>
<string name="use_camera_button">Камера</string>
<string name="from_gallery_button">Галерея</string>
<string name="choose_file">Файлы\n(v2.0)</string>
<string name="choose_file">Файлы</string>
<!-- help - ChatHelpView.kt -->
<string name="thank_you_for_installing_simplex">Спасибо, что установили <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
@@ -379,7 +379,8 @@
<string name="icon_descr_audio_call">аудиозвонок</string>
<!-- Call settings -->
<string name="call_settings">Настройки звонков</string>
<string name="call_settings">Аудио- и видеозвонки</string>
<string name="your_calls">Ваши звонки</string>
<string name="connect_calls_via_relay">Соединяться через сервер (relay)</string>
<string name="call_on_lock_screen">Звонки на экране блокировки:</string>
<string name="accept_call_on_lock_screen">Принимать</string>
@@ -421,4 +422,10 @@
<string name="integrity_msg_duplicate">повторное сообщение</string>
<string name="alert_title_skipped_messages">Пропущенные сообщения</string>
<string name="alert_text_skipped_messages_it_can_happen_when">Это может случится, когда:\n1. Сервер удалил сообщения, если они не были доставлены в течение 30 дней.\n2. Сервер, через который вы получаете сообщения от контакта, был обновлён и перезапущен.\n3. Соединение компроментировано.\nПожалуйста, соединитесь с девелоперами через Настройки, чтобы получать уведомления о серверах.\nМы планируем добавить избыточную доставку сообщений, чтобы не терять сообщения.</string>
<!-- Privacy settings -->
<string name="privacy_and_security">Конфиденциальность</string>
<string name="your_privacy">Конфиденциальность</string>
<string name="auto_accept_images">Автоприем изображений</string>
<string name="send_link_previews">Отправлять картинки ссылок</string>
</resources>
@@ -169,7 +169,7 @@
<string name="toast_permission_denied">Permission Denied!</string>
<string name="use_camera_button">Use Camera</string>
<string name="from_gallery_button">From Gallery</string>
<string name="choose_file">Choose file\n(new in v2.0)</string>
<string name="choose_file">Choose file</string>
<!-- help - ChatHelpView.kt -->
<string name="thank_you_for_installing_simplex">Thank you for installing <xliff:g id="appNameFull">SimpleX Chat</xliff:g>!</string>
@@ -381,7 +381,8 @@
<string name="icon_descr_audio_call">audio call</string>
<!-- Call settings -->
<string name="call_settings">Call settings</string>
<string name="call_settings">Audio &amp; video calls</string>
<string name="your_calls">Your calls</string>
<string name="connect_calls_via_relay">Connect via relay</string>
<string name="call_on_lock_screen">Calls on lock screen:</string>
<string name="accept_call_on_lock_screen">Accept</string>
@@ -423,4 +424,10 @@
<string name="integrity_msg_duplicate">duplicate message</string>
<string name="alert_title_skipped_messages">Skipped messages</string>
<string name="alert_text_skipped_messages_it_can_happen_when">It can happen when:\n1. The messages expire on the server if they were not received for 30 days,\n2. The server you use to receive the messages from this contact was updated and restarted.\n3. The connection is compromised.\nPlease connect to the developers via Settings to receive the updates about the servers.\nWe will be adding server redundancy to prevent lost messages.</string>
<!-- Privacy settings -->
<string name="privacy_and_security">Privacy &amp; security</string>
<string name="your_privacy">Your privacy</string>
<string name="auto_accept_images">Auto-accept images</string>
<string name="send_link_previews">Send link previews</string>
</resources>