1+ import AVFoundation
12import CoreServices
23import ImageIO
34import InlineKit
5+ import Logger
6+ import MobileCoreServices
47import PhotosUI
58import SwiftUI
69import UIKit
@@ -100,7 +103,9 @@ class TextViewContainer: UIView {
100103
101104// MARK: - Main ComposeView Implementation
102105
103- class ComposeView : UIView , NSTextLayoutManagerDelegate {
106+ class ComposeView : UIView , NSTextLayoutManagerDelegate ,
107+ UIImagePickerControllerDelegate & UINavigationControllerDelegate
108+ {
104109 // MARK: Configuration Constants
105110
106111 static let minHeight : CGFloat = 42.0
@@ -262,7 +267,26 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate {
262267 button. configuration = config
263268 button. layer. cornerRadius = Self . minHeight / 2
264269 button. clipsToBounds = true
265- button. addTarget ( self , action: #selector( plusTapped) , for: . touchUpInside)
270+
271+ let libraryAction = UIAction (
272+ title: " Photos " ,
273+ image: UIImage ( systemName: " photo " ) ,
274+ handler: { [ weak self] _ in
275+ self ? . presentPicker ( )
276+ }
277+ )
278+
279+ let cameraAction = UIAction (
280+ title: " Camera " ,
281+ image: UIImage ( systemName: " camera " ) ,
282+ handler: { _ in
283+ self . presentCamera ( )
284+ }
285+ )
286+
287+ button. menu = UIMenu ( children: [ libraryAction, cameraAction] )
288+ button. showsMenuAsPrimaryAction = true
289+
266290 return button
267291 }
268292
@@ -274,8 +298,6 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate {
274298 else { return }
275299 guard let chatId else { return }
276300
277- let messageText = text
278-
279301 let replyToMessageId = ChatState . shared. getState ( peer: peerId) . replyingMessageId
280302 let canSend = !text. isEmpty
281303
@@ -303,7 +325,7 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate {
303325 }
304326 }
305327
306- @objc private func plusTapped ( ) {
328+ @objc private func presentPicker ( ) {
307329 guard let windowScene = window? . windowScene else { return }
308330
309331 var configuration = PHPickerConfiguration ( photoLibrary: . shared( ) )
@@ -507,14 +529,48 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate {
507529 let picker = topmostVC. presentingViewController as? PHPickerViewController
508530
509531 topmostVC. dismiss ( animated: true ) { [ weak self] in
510- // Dismiss the picker if it exists
511532 picker? . dismiss ( animated: true )
512533 self ? . selectedImage = nil
513534 self ? . previewViewModel. caption = " "
514535 self ? . previewViewModel. isPresented = false
515536 }
516537 }
517538
539+ // MARK: - Camera Handling
540+
541+ private func presentCamera( ) {
542+ let status = AVCaptureDevice . authorizationStatus ( for: . video)
543+
544+ switch status {
545+ case . notDetermined:
546+ AVCaptureDevice . requestAccess ( for: . video) { [ weak self] granted in
547+ if granted {
548+ DispatchQueue . main. async {
549+ self ? . showCameraPicker ( )
550+ }
551+ }
552+ }
553+ case . authorized:
554+ showCameraPicker ( )
555+ default :
556+ Log . shared. error ( " Failed to presentCamera " )
557+ }
558+ }
559+
560+ private func showCameraPicker( ) {
561+ let picker = UIImagePickerController ( )
562+ picker. sourceType = . camera
563+ picker. delegate = self
564+ picker. allowsEditing = false
565+
566+ if let windowScene = window? . windowScene,
567+ let keyWindow = windowScene. windows. first ( where: { $0. isKeyWindow } ) ,
568+ let rootVC = keyWindow. rootViewController
569+ {
570+ rootVC. present ( picker, animated: true )
571+ }
572+ }
573+
518574 private func sendImage( _ image: UIImage , caption: String ) {
519575 guard let peerId else { return }
520576
@@ -592,6 +648,24 @@ class ComposeView: UIView, NSTextLayoutManagerDelegate {
592648 responder = nextResponder
593649 }
594650 }
651+
652+ func imagePickerController(
653+ _ picker: UIImagePickerController ,
654+ didFinishPickingMediaWithInfo info: [ UIImagePickerController . InfoKey : Any ]
655+ ) {
656+ guard let image = info [ . originalImage] as? UIImage else {
657+ picker. dismiss ( animated: true )
658+ return
659+ }
660+
661+ picker. dismiss ( animated: true ) { [ weak self] in
662+ self ? . handleDroppedImage ( image)
663+ }
664+ }
665+
666+ func imagePickerControllerDidCancel( _ picker: UIImagePickerController ) {
667+ picker. dismiss ( animated: true )
668+ }
595669}
596670
597671// MARK: - User Interaction Handling
0 commit comments