|
1 | 1 | import AVFoundation
|
| 2 | +import Combine |
2 | 3 | import CoreServices
|
3 | 4 | import ImageIO
|
4 | 5 | import InlineKit
|
@@ -122,6 +123,7 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate,
|
122 | 123 | private let buttonSize: CGSize = .init(width: 36, height: 36)
|
123 | 124 | private var overlayView: UIView?
|
124 | 125 | private var isOverlayVisible = false
|
| 126 | + private var phaseObserver: AnyCancellable? |
125 | 127 |
|
126 | 128 | // MARK: UI Components
|
127 | 129 |
|
@@ -160,8 +162,8 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate,
|
160 | 162 |
|
161 | 163 | override init(frame: CGRect) {
|
162 | 164 | super.init(frame: frame)
|
163 |
| - |
164 | 165 | setupViews()
|
| 166 | + setupScenePhaseObserver() |
165 | 167 | }
|
166 | 168 |
|
167 | 169 | @available(*, unavailable)
|
@@ -315,7 +317,7 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate,
|
315 | 317 | )
|
316 | 318 |
|
317 | 319 | UnreadManager.shared.readAll(peerId, chatId: chatId)
|
318 |
| - |
| 320 | + clearDraft() |
319 | 321 | ChatState.shared.clearReplyingMessageId(peer: peerId)
|
320 | 322 | sendMessageHaptic()
|
321 | 323 | textViewContainer.textView.text = ""
|
@@ -427,16 +429,7 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate,
|
427 | 429 | }
|
428 | 430 |
|
429 | 431 | override func removeFromSuperview() {
|
430 |
| - if let text = textViewContainer.textView.text { |
431 |
| - guard let peerId else { return } |
432 |
| - Task { |
433 |
| - do { |
434 |
| - try await DataManager.shared.updateDialog(peerId: peerId, draft: text.isEmpty ? nil : text) |
435 |
| - } catch { |
436 |
| - print("Failed to save draft", error) |
437 |
| - } |
438 |
| - } |
439 |
| - } |
| 432 | + saveDraft() |
440 | 433 | super.removeFromSuperview()
|
441 | 434 | }
|
442 | 435 |
|
@@ -666,6 +659,62 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate,
|
666 | 659 | func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
667 | 660 | picker.dismiss(animated: true)
|
668 | 661 | }
|
| 662 | + |
| 663 | + private func setupScenePhaseObserver() { |
| 664 | + // Save draft when app moves to background |
| 665 | + NotificationCenter.default.addObserver( |
| 666 | + self, |
| 667 | + selector: #selector(saveCurrentDraft), |
| 668 | + name: UIApplication.didEnterBackgroundNotification, |
| 669 | + object: nil |
| 670 | + ) |
| 671 | + |
| 672 | + // Save draft when force-quits the app from the app switcher |
| 673 | + NotificationCenter.default.addObserver( |
| 674 | + self, |
| 675 | + selector: #selector(saveCurrentDraft), |
| 676 | + name: UIApplication.willTerminateNotification, |
| 677 | + object: nil |
| 678 | + ) |
| 679 | + |
| 680 | + // Save draft when app becomes inactive |
| 681 | + NotificationCenter.default.addObserver( |
| 682 | + self, |
| 683 | + selector: #selector(saveCurrentDraft), |
| 684 | + name: UIApplication.willResignActiveNotification, |
| 685 | + object: nil |
| 686 | + ) |
| 687 | + } |
| 688 | + |
| 689 | + @objc private func saveCurrentDraft() { |
| 690 | + saveDraft() |
| 691 | + } |
| 692 | + |
| 693 | + private func saveDraft() { |
| 694 | + guard let peerId else { return } |
| 695 | + |
| 696 | + if let text = textViewContainer.textView.text, !text.isEmpty { |
| 697 | + Task { |
| 698 | + do { |
| 699 | + try await DataManager.shared.updateDialog(peerId: peerId, draft: text) |
| 700 | + } catch { |
| 701 | + print("Failed to save draft", error) |
| 702 | + } |
| 703 | + } |
| 704 | + } |
| 705 | + } |
| 706 | + |
| 707 | + private func clearDraft() { |
| 708 | + guard let peerId else { return } |
| 709 | + |
| 710 | + Task { |
| 711 | + do { |
| 712 | + try await DataManager.shared.updateDialog(peerId: peerId, draft: nil) |
| 713 | + } catch { |
| 714 | + print("Failed to clear draft", error) |
| 715 | + } |
| 716 | + } |
| 717 | + } |
669 | 718 | }
|
670 | 719 |
|
671 | 720 | // MARK: - User Interaction Handling
|
|
0 commit comments