diff --git a/deltachat-ios/Chat/ChatViewController.swift b/deltachat-ios/Chat/ChatViewController.swift index bc1364859..292655921 100644 --- a/deltachat-ios/Chat/ChatViewController.swift +++ b/deltachat-ios/Chat/ChatViewController.swift @@ -708,7 +708,7 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { messageInputBar.inputTextView.resignFirstResponder() } else { messageInputBar.setMiddleContentView(messageInputBar.inputTextView, animated: false) - messageInputBar.setLeftStackViewWidthConstant(to: 40, animated: false) + messageInputBar.setLeftStackViewWidthConstant(to: draft.sendEditRequestFor == nil ? 40 : 0, animated: false) messageInputBar.setRightStackViewWidthConstant(to: 40, animated: false) messageInputBar.padding = UIEdgeInsets(top: 6, left: 6, bottom: 6, right: 12) inputAccessoryView = messageInputBar @@ -1665,6 +1665,15 @@ class ChatViewController: UITableViewController, UITableViewDropDelegate { replyToMessage(at: indexPath) } + private func editSentMessage(at indexPath: IndexPath) { + let message = dcContext.getMessage(id: messageIds[indexPath.row]) + + draft.clear() + draft.sendEditRequestFor = message.id + configureDraftArea(draft: draft) + messageInputBar.inputTextView.text = message.text + } + private func toggleSave(at indexPath: IndexPath) { let message = dcContext.getMessage(id: messageIds[indexPath.row]) if message.savedMessageId != 0 { @@ -1909,6 +1918,12 @@ extension ChatViewController { UIAction.menuAction(localizationKey: "forward", systemImageName: "arrowshape.turn.up.forward", indexPath: indexPath, action: forward) ) + if message.isFromCurrentSender && message.hasText && !message.isMarkerOrInfo && dcChat.canSend { + children.append( + UIAction.menuAction(localizationKey: "global_menu_edit_desktop", systemImageName: "pencil", indexPath: indexPath, action: editSentMessage) + ) + } + if !dcChat.isSelfTalk && message.canSave { if message.savedMessageId != 0 { children.append( @@ -2364,7 +2379,10 @@ extension ChatViewController: InputBarAccessoryViewDelegate { func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) { let trimmedText = text.replacingOccurrences(of: "\u{FFFC}", with: "", options: .literal, range: nil) .trimmingCharacters(in: .whitespacesAndNewlines) - if let filePath = draft.attachment, let viewType = draft.viewType { + + if let sendEditRequestFor = draft.sendEditRequestFor { + dcContext.sendEditRequest(msgId: sendEditRequestFor, newText: text) + } else if let filePath = draft.attachment, let viewType = draft.viewType { switch viewType { case DC_MSG_GIF, DC_MSG_IMAGE, DC_MSG_FILE, DC_MSG_VIDEO, DC_MSG_WEBXDC, DC_MSG_VCARD: self.sendAttachmentMessage(viewType: viewType, filePath: filePath, message: trimmedText, quoteMessage: draft.quoteMessage) @@ -2392,9 +2410,15 @@ extension ChatViewController: InputBarAccessoryViewDelegate { // MARK: - DraftPreviewDelegate extension ChatViewController: DraftPreviewDelegate { func onCancelQuote() { - draft.setQuote(quotedMsg: nil) - configureDraftArea(draft: draft) - focusInputTextView() + if draft.sendEditRequestFor != nil { + draft.clear() + draftArea.cancel() + messageInputBar.inputTextView.text = nil + } else { + draft.setQuote(quotedMsg: nil) + configureDraftArea(draft: draft) + focusInputTextView() + } } func onCancelAttachment() { diff --git a/deltachat-ios/Chat/DraftModel.swift b/deltachat-ios/Chat/DraftModel.swift index a8d2388b8..f193106d7 100644 --- a/deltachat-ios/Chat/DraftModel.swift +++ b/deltachat-ios/Chat/DraftModel.swift @@ -7,7 +7,8 @@ public class DraftModel { var dcContext: DcContext var text: String? let chatId: Int - var isEditing: Bool = false + var isEditing: Bool = false // multi edit + var sendEditRequestFor: Int? var quoteMessage: DcMsg? { return draftMsg?.quoteMessage } @@ -39,6 +40,7 @@ public class DraftModel { draftMsg = dcContext.newMessage(viewType: DC_MSG_TEXT) } draftMsg?.quoteMessage = quotedMsg + sendEditRequestFor = nil } public func setAttachment(viewType: Int32?, path: String?, mimetype: String? = nil) { @@ -62,6 +64,11 @@ public class DraftModel { } public func save(context: DcContext) { + if sendEditRequestFor != nil { + clear() + return + } + if (text?.isEmpty ?? true) && (draftMsg == nil || quoteMessage == nil && attachment == nil) { self.clear() @@ -82,6 +89,7 @@ public class DraftModel { public func clear() { text = nil draftMsg = nil + sendEditRequestFor = nil dcContext.setDraft(chatId: chatId, message: nil) } } diff --git a/deltachat-ios/Chat/Views/QuotePreview.swift b/deltachat-ios/Chat/Views/QuotePreview.swift index 0a51eb4b4..94ad69b0c 100644 --- a/deltachat-ios/Chat/Views/QuotePreview.swift +++ b/deltachat-ios/Chat/Views/QuotePreview.swift @@ -26,7 +26,14 @@ public class QuotePreview: DraftPreview { } override public func configure(draft: DraftModel) { - if !draft.isEditing, + if !draft.isEditing, let sendEditRequestFor = draft.sendEditRequestFor { + quoteView.senderTitle.text = String.localized("edit_message") + quoteView.senderTitle.textColor = DcColors.unknownSender + quoteView.quote.text = draft.dcContext.getMessage(id: sendEditRequestFor).text + quoteView.setImagePreview(nil) + quoteView.citeBar.backgroundColor = DcColors.unknownSender + isHidden = false + } else if !draft.isEditing, let quoteText = draft.quoteText { quoteView.quote.text = quoteText compactView = draft.attachment != nil diff --git a/deltachat-ios/Chat/Views/StatusView.swift b/deltachat-ios/Chat/Views/StatusView.swift index 1551c1705..65bf69282 100644 --- a/deltachat-ios/Chat/Views/StatusView.swift +++ b/deltachat-ios/Chat/Views/StatusView.swift @@ -5,6 +5,7 @@ import DcCore public class StatusView: UIView { private let contentStackView: UIStackView let dateLabel: UILabel + private let editedLabel: UILabel private let padlockView: UIImageView private let locationView: UIImageView private let stateView: UIImageView @@ -16,6 +17,11 @@ public class StatusView: UIView { dateLabel.translatesAutoresizingMaskIntoConstraints = false dateLabel.font = UIFont.preferredFont(for: .caption1, weight: .regular) + editedLabel = UILabel() + editedLabel.text = String.localized("edited") + editedLabel.translatesAutoresizingMaskIntoConstraints = false + editedLabel.font = UIFont.preferredFont(for: .caption1, weight: .regular) + padlockView = UIImageView() padlockView.translatesAutoresizingMaskIntoConstraints = false locationView = UIImageView() @@ -25,9 +31,9 @@ public class StatusView: UIView { savedView = UIImageView() savedView.translatesAutoresizingMaskIntoConstraints = false - contentStackView = UIStackView(arrangedSubviews: [savedView, padlockView, dateLabel, locationView, stateView]) + contentStackView = UIStackView(arrangedSubviews: [savedView, padlockView, dateLabel, editedLabel, locationView, stateView]) contentStackView.alignment = .center - contentStackView.spacing = 0 + contentStackView.spacing = 2 contentStackView.translatesAutoresizingMaskIntoConstraints = false super.init(frame: frame) @@ -68,6 +74,7 @@ public class StatusView: UIView { public func prepareForReuse() { dateLabel.text = nil + editedLabel.isHidden = true padlockView.isHidden = true locationView.isHidden = true savedView.isHidden = true @@ -77,6 +84,8 @@ public class StatusView: UIView { public func update(message: DcMsg, tintColor: UIColor) { dateLabel.text = message.formattedSentDate() dateLabel.textColor = tintColor + editedLabel.isHidden = !message.isEdited + editedLabel.textColor = tintColor if message.showPadlock() { padlockView.image = UIImage(named: "ic_lock")?.maskWithColor(color: tintColor) diff --git a/deltachat-ios/DC/DcContext.swift b/deltachat-ios/DC/DcContext.swift index fc60a51ff..f535b1b59 100644 --- a/deltachat-ios/DC/DcContext.swift +++ b/deltachat-ios/DC/DcContext.swift @@ -62,6 +62,10 @@ public class DcContext { dc_send_msg(contextPointer, UInt32(chatId), message.messagePointer) } + public func sendEditRequest(msgId: Int, newText: String) { + dc_send_edit_request(contextPointer, UInt32(msgId), newText) + } + public func downloadFullMessage(id: Int) { dc_download_full_msg(contextPointer, Int32(id)) } diff --git a/deltachat-ios/DC/DcMsg.swift b/deltachat-ios/DC/DcMsg.swift index 5dd0e9369..9a400f72e 100644 --- a/deltachat-ios/DC/DcMsg.swift +++ b/deltachat-ios/DC/DcMsg.swift @@ -31,6 +31,10 @@ public class DcMsg { return dc_msg_is_forwarded(messagePointer) != 0 } + public var isEdited: Bool { + return dc_msg_is_edited(messagePointer) != 0 + } + public var isValid: Bool { return messagePointer != nil } @@ -43,7 +47,6 @@ public class DcMsg { return Int(dc_msg_get_id(messagePointer)) } - public var fromContactId: Int { return Int(dc_msg_get_from_id(messagePointer)) } @@ -103,6 +106,10 @@ public class DcMsg { } } + public var hasText: Bool { + return !(text ?? "").isEmpty + } + public var subject: String { guard let cString = dc_msg_get_subject(messagePointer) else { return "" } let swiftString = String(cString: cString)