Merge branch 'master' into master-ios

This commit is contained in:
spaced4ndy
2023-05-03 20:26:46 +04:00
14 changed files with 85 additions and 37 deletions
@@ -118,7 +118,7 @@ data class ComposeState(
val attachmentDisabled: Boolean
get() {
if (editing || liveMessage != null) return true
if (editing || liveMessage != null || inProgress) return true
return when (preview) {
ComposePreview.NoPreview -> false
is ComposePreview.CLinkPreview -> false
@@ -623,23 +623,27 @@ fun ComposeView(
fun previewView() {
when (val preview = composeState.value.preview) {
ComposePreview.NoPreview -> {}
is ComposePreview.CLinkPreview -> ComposeLinkView(preview.linkPreview, ::cancelLinkPreview)
is ComposePreview.CLinkPreview -> ComposeLinkView(
preview.linkPreview,
::cancelLinkPreview,
cancelEnabled = !composeState.value.inProgress
)
is ComposePreview.MediaPreview -> ComposeImageView(
preview,
::cancelImages,
cancelEnabled = !composeState.value.editing
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress
)
is ComposePreview.VoicePreview -> ComposeVoiceView(
preview.voice,
preview.durationMs,
preview.finished,
cancelEnabled = !composeState.value.editing,
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress,
::cancelVoice
)
is ComposePreview.FilePreview -> ComposeFileView(
preview.fileName,
::cancelFile,
cancelEnabled = !composeState.value.editing
cancelEnabled = !composeState.value.editing && !composeState.value.inProgress
)
}
}
@@ -657,6 +661,14 @@ fun ComposeView(
}
}
// In case a user sent something, state is in progress, the user rotates a screen to different orientation.
// Without clearing the state the user will be unable to send anything until re-enters ChatView
LaunchedEffect(Unit) {
if (composeState.value.inProgress) {
clearState()
}
}
LaunchedEffect(chatModel.sharedContent.value) {
// Important. If it's null, don't do anything, chat is not closed yet but will be after a moment
if (chatModel.chatId.value == null) return@LaunchedEffect
@@ -744,6 +756,8 @@ fun ComposeView(
resetLinkPreview()
clearCurrentDraft()
deleteUnusedFiles()
} else if (composeState.value.inProgress) {
clearCurrentDraft()
} else if (!composeState.value.empty) {
if (cs.preview is ComposePreview.VoicePreview && !cs.preview.finished) {
composeState.value = cs.copy(preview = cs.preview.copy(finished = true))
@@ -79,7 +79,7 @@ fun SendMsgView(
val showDeleteTextButton = rememberSaveable { mutableStateOf(false) }
NativeKeyboard(composeState, textStyle, showDeleteTextButton, userIsObserver, onMessageChange)
// Disable clicks on text field
if (cs.preview is ComposePreview.VoicePreview || !userCanSend) {
if (cs.preview is ComposePreview.VoicePreview || !userCanSend || cs.inProgress) {
Box(Modifier
.matchParentSize()
.clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = {
@@ -250,14 +250,20 @@ private fun NativeKeyboard(
Log.e(chat.simplex.app.TAG, e.stackTraceToString())
}
}
editText.doOnTextChanged { text, _, _, _ -> onMessageChange(text.toString()) }
editText.doOnTextChanged { text, _, _, _ ->
if (!composeState.value.inProgress) {
onMessageChange(text.toString())
} else if (text.toString() != composeState.value.message) {
editText.setText(composeState.value.message)
}
}
editText.doAfterTextChanged { text -> if (composeState.value.preview is ComposePreview.VoicePreview && text.toString() != "") editText.setText("") }
editText
}) {
it.setTextColor(textColor.toArgb())
it.textSize = textStyle.value.fontSize.value
DrawableCompat.setTint(it.background, tintColor.toArgb())
it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview
it.isFocusable = composeState.value.preview !is ComposePreview.VoicePreview && !cs.inProgress
it.isFocusableInTouchMode = it.isFocusable
if (cs.message != it.text.toString()) {
it.setText(cs.message)
@@ -270,7 +276,7 @@ private fun NativeKeyboard(
imm.showSoftInput(it, InputMethodManager.SHOW_IMPLICIT)
showKeyboard = false
}
showDeleteTextButton.value = it.lineCount >= 4
showDeleteTextButton.value = it.lineCount >= 4 && !cs.inProgress
}
if (composeState.value.preview is ComposePreview.VoicePreview) {
ComposeOverlay(R.string.voice_message_send_text, textStyle, padding)
@@ -77,7 +77,7 @@ suspend fun getLinkPreview(url: String): LinkPreview? {
}
@Composable
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit) {
fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancelEnabled: Boolean) {
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
Row(
Modifier.fillMaxWidth().padding(top = 8.dp).background(sentColor),
@@ -109,13 +109,15 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit) {
)
}
}
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
if (cancelEnabled) {
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
}
}
}
}
@@ -193,7 +195,7 @@ fun PreviewChatItemLinkView() {
@Composable
fun PreviewComposeLinkView() {
SimpleXTheme {
ComposeLinkView(LinkPreview.sampleData) { -> }
ComposeLinkView(LinkPreview.sampleData, cancelPreview = { -> }, true)
}
}
@@ -201,6 +203,6 @@ fun PreviewComposeLinkView() {
@Composable
fun PreviewComposeLinkViewLoading() {
SimpleXTheme {
ComposeLinkView(null) { -> }
ComposeLinkView(null, cancelPreview = { -> }, true)
}
}
File diff suppressed because one or more lines are too long
@@ -154,7 +154,7 @@ struct ComposeState {
}
var attachmentDisabled: Bool {
if editing || liveMessage != nil { return true }
if editing || liveMessage != nil || inProgress { return true }
switch preview {
case .noPreview: return false
case .linkPreview: return false
@@ -427,6 +427,8 @@ struct ComposeView: View {
clearCurrentDraft()
sendMessage()
resetLinkPreview()
} else if (composeState.inProgress) {
clearCurrentDraft()
} else if !composeState.empty {
saveCurrentDraft()
} else {
@@ -522,7 +524,11 @@ struct ComposeView: View {
case .noPreview:
EmptyView()
case let .linkPreview(linkPreview: preview):
ComposeLinkView(linkPreview: preview, cancelPreview: cancelLinkPreview)
ComposeLinkView(
linkPreview: preview,
cancelPreview: cancelLinkPreview,
cancelEnabled: !composeState.inProgress
)
case let .mediaPreviews(mediaPreviews: media):
ComposeImageView(
images: media.map { (img, _) in img },
@@ -530,7 +536,7 @@ struct ComposeView: View {
composeState = composeState.copy(preview: .noPreview)
chosenMedia = []
},
cancelEnabled: !composeState.editing)
cancelEnabled: !composeState.editing && !composeState.inProgress)
case let .voicePreview(recordingFileName, _):
ComposeVoiceView(
recordingFileName: recordingFileName,
@@ -540,7 +546,7 @@ struct ComposeView: View {
cancelVoiceMessageRecording($0)
clearState()
},
cancelEnabled: !composeState.editing,
cancelEnabled: !composeState.editing && !composeState.inProgress,
stopPlayback: $stopPlayback
)
case let .filePreview(fileName, _):
@@ -549,7 +555,7 @@ struct ComposeView: View {
cancelFile: {
composeState = composeState.copy(preview: .noPreview)
},
cancelEnabled: !composeState.editing)
cancelEnabled: !composeState.editing && !composeState.inProgress)
}
}
@@ -13,6 +13,7 @@ import PhotosUI
struct NativeTextEditor: UIViewRepresentable {
@Binding var text: String
@Binding var disableEditing: Bool
let height: CGFloat
let font: UIFont
@FocusState.Binding var focused: Bool
@@ -26,7 +27,11 @@ struct NativeTextEditor: UIViewRepresentable {
field.textAlignment = alignment == .leading ? .left : .right
field.autocapitalizationType = .sentences
field.setOnTextChangedListener { newText, images in
text = newText
if !disableEditing {
text = newText
} else {
field.text = text
}
if !images.isEmpty {
onImagesAdded(images)
}
@@ -140,6 +145,7 @@ struct NativeTextEditor_Previews: PreviewProvider{
@FocusState var keyboardVisible: Bool
return NativeTextEditor(
text: Binding.constant("Hello, world!"),
disableEditing: Binding.constant(false),
height: 100,
font: UIFont.preferredFont(forTextStyle: .body),
focused: $keyboardVisible,
@@ -65,6 +65,7 @@ struct SendMessageView: View {
NativeTextEditor(
text: $composeState.message,
disableEditing: $composeState.inProgress,
height: teHeight,
font: teUiFont,
focused: $keyboardVisible,
@@ -83,7 +84,7 @@ struct SendMessageView: View {
.padding([.bottom, .trailing], 3)
} else {
VStack(alignment: .trailing) {
if teHeight > 100 {
if teHeight > 100 && !composeState.inProgress {
deleteTextButton()
Spacer()
}
@@ -46,7 +46,9 @@ struct GroupChatInfoView: View {
if groupInfo.canEdit {
editGroupButton()
}
addOrEditWelcomeMessage()
if groupInfo.groupProfile.description != nil || groupInfo.canEdit {
addOrEditWelcomeMessage()
}
groupPreferencesButton($groupInfo)
} header: {
Text("")
+1
View File
@@ -105,5 +105,6 @@ mkChatOpts BroadcastBotOpts {coreOptions} =
chatServerPort = Nothing,
optFilesFolder = Nothing,
allowInstantFiles = True,
muteNotifications = True,
maintenance = False
}
+1
View File
@@ -129,6 +129,7 @@ mobileChatOpts dbFilePrefix dbKey =
chatServerPort = Nothing,
optFilesFolder = Nothing,
allowInstantFiles = True,
muteNotifications = True,
maintenance = True
}
+7
View File
@@ -36,6 +36,7 @@ data ChatOpts = ChatOpts
chatServerPort :: Maybe String,
optFilesFolder :: Maybe FilePath,
allowInstantFiles :: Bool,
muteNotifications :: Bool,
maintenance :: Bool
}
@@ -221,6 +222,11 @@ chatOptsP appDir defaultDbFileName = do
<> short 'f'
<> help "Send and receive instant files without acceptance"
)
muteNotifications <-
switch
( long "mute"
<> help "Mute notifications"
)
maintenance <-
switch
( long "maintenance"
@@ -235,6 +241,7 @@ chatOptsP appDir defaultDbFileName = do
chatServerPort,
optFilesFolder,
allowInstantFiles,
muteNotifications,
maintenance
}
+5 -5
View File
@@ -3790,7 +3790,7 @@ getDirectChatPreviews_ db user@User {userId} = do
WHERE item_status = ?
GROUP BY contact_id
) ChatStats ON ChatStats.contact_id = ct.contact_id
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.contact_id = i.contact_id
LEFT JOIN chat_items ri ON ri.user_id = i.user_id AND ri.contact_id = i.contact_id AND ri.shared_msg_id = i.quoted_shared_msg_id
WHERE ct.user_id = ?
AND ((c.conn_level = 0 AND c.via_group_link = 0) OR ct.contact_used = 1)
AND c.connection_id = (
@@ -4006,7 +4006,7 @@ getDirectChatItemsLast db User {userId} contactId count search = ExceptT $ do
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent
FROM chat_items i
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.contact_id = i.contact_id
LEFT JOIN chat_items ri ON ri.user_id = i.user_id AND ri.contact_id = i.contact_id AND ri.shared_msg_id = i.quoted_shared_msg_id
WHERE i.user_id = ? AND i.contact_id = ? AND i.item_text LIKE '%' || ? || '%'
ORDER BY i.chat_item_id DESC
LIMIT ?
@@ -4037,7 +4037,7 @@ getDirectChatAfter_ db user@User {userId} contactId afterChatItemId count search
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent
FROM chat_items i
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.contact_id = i.contact_id
LEFT JOIN chat_items ri ON ri.user_id = i.user_id AND ri.contact_id = i.contact_id AND ri.shared_msg_id = i.quoted_shared_msg_id
WHERE i.user_id = ? AND i.contact_id = ? AND i.item_text LIKE '%' || ? || '%'
AND i.chat_item_id > ?
ORDER BY i.chat_item_id ASC
@@ -4069,7 +4069,7 @@ getDirectChatBefore_ db user@User {userId} contactId beforeChatItemId count sear
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent
FROM chat_items i
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.contact_id = i.contact_id
LEFT JOIN chat_items ri ON ri.user_id = i.user_id AND ri.contact_id = i.contact_id AND ri.shared_msg_id = i.quoted_shared_msg_id
WHERE i.user_id = ? AND i.contact_id = ? AND i.item_text LIKE '%' || ? || '%'
AND i.chat_item_id < ?
ORDER BY i.chat_item_id DESC
@@ -4475,7 +4475,7 @@ getDirectChatItem db User {userId} contactId itemId = ExceptT $ do
ri.chat_item_id, i.quoted_shared_msg_id, i.quoted_sent_at, i.quoted_content, i.quoted_sent
FROM chat_items i
LEFT JOIN files f ON f.chat_item_id = i.chat_item_id
LEFT JOIN chat_items ri ON ri.shared_msg_id = i.quoted_shared_msg_id AND ri.contact_id = i.contact_id
LEFT JOIN chat_items ri ON ri.user_id = i.user_id AND ri.contact_id = i.contact_id AND ri.shared_msg_id = i.quoted_shared_msg_id
WHERE i.user_id = ? AND i.contact_id = ? AND i.chat_item_id = ?
|]
(userId, contactId, itemId)
+2 -2
View File
@@ -41,8 +41,8 @@ terminalChatConfig =
simplexChatTerminal :: WithTerminal t => ChatConfig -> ChatOpts -> t -> IO ()
simplexChatTerminal cfg opts t = do
sendToast <- initializeNotifications
handle checkDBKeyError . simplexChatCore cfg opts (Just sendToast) $ \u cc -> do
sendToast <- if muteNotifications opts then pure Nothing else Just <$> initializeNotifications
handle checkDBKeyError . simplexChatCore cfg opts sendToast $ \u cc -> do
ct <- newChatTerminal t
when (firstTime cc) . printToTerminal ct $ chatWelcome u
runChatTerminal ct cc
+1
View File
@@ -73,6 +73,7 @@ testOpts =
chatServerPort = Nothing,
optFilesFolder = Nothing,
allowInstantFiles = True,
muteNotifications = True,
maintenance = False
}