Skip to content

Commit 8eb1f59

Browse files
committed
Add camera
1 parent 04ede57 commit 8eb1f59

File tree

2 files changed

+83
-6
lines changed

2 files changed

+83
-6
lines changed

apple/Inline.xcodeproj/project.pbxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@
339339
INFOPLIST_FILE = InlineIOS/Info.plist;
340340
INFOPLIST_KEY_CFBundleDisplayName = Inline;
341341
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
342+
INFOPLIST_KEY_NSCameraUsageDescription = "Inline needs access to your camera to take photos";
342343
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
343344
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
344345
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -377,6 +378,7 @@
377378
INFOPLIST_FILE = InlineIOS/Info.plist;
378379
INFOPLIST_KEY_CFBundleDisplayName = Inline;
379380
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
381+
INFOPLIST_KEY_NSCameraUsageDescription = "Inline needs access to your camera to take photos";
380382
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
381383
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
382384
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -700,6 +702,7 @@
700702
INFOPLIST_FILE = InlineIOS/Info.plist;
701703
INFOPLIST_KEY_CFBundleDisplayName = Inline;
702704
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
705+
INFOPLIST_KEY_NSCameraUsageDescription = "Inline needs access to your camera to take photos";
703706
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
704707
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
705708
INFOPLIST_KEY_UILaunchScreen_Generation = YES;

apple/InlineIOS/Chat/ComposeView.swift

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import AVFoundation
12
import CoreServices
23
import ImageIO
34
import InlineKit
5+
import Logger
6+
import MobileCoreServices
47
import PhotosUI
58
import SwiftUI
69
import 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

Comments
 (0)