iOS 2.5.1 - Fixed Camera Rotation
This commit is contained in:
@@ -465,7 +465,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 37;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -487,7 +487,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 2.5.0;
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -513,7 +513,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 37;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -535,7 +535,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.6;
|
||||
MARKETING_VERSION = 2.5.0;
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -602,7 +602,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 37;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
||||
@@ -613,7 +613,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.5.0;
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -632,7 +632,7 @@
|
||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 37;
|
||||
CURRENT_PROJECT_VERSION = 38;
|
||||
DEVELOPMENT_TEAM = 4BC9Y2LL4B;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SessionStatusLive/Info.plist;
|
||||
@@ -643,7 +643,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.5.0;
|
||||
MARKETING_VERSION = 2.5.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
||||
Binary file not shown.
@@ -1,52 +1,104 @@
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
/// A native iOS camera picker presented from a hosting controller so it can
|
||||
/// respect all supported interface orientations. Present with `.fullScreenCover()`.
|
||||
struct CameraImagePicker: UIViewControllerRepresentable {
|
||||
@Binding var isPresented: Bool
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
let onImageCaptured: (UIImage) -> Void
|
||||
|
||||
func makeUIViewController(context: Context) -> UIImagePickerController {
|
||||
let picker = UIImagePickerController()
|
||||
picker.delegate = context.coordinator
|
||||
picker.sourceType = .camera
|
||||
picker.cameraCaptureMode = .photo
|
||||
picker.cameraDevice = .rear
|
||||
picker.allowsEditing = false
|
||||
return picker
|
||||
func makeUIViewController(context: Context) -> CameraHostViewController {
|
||||
let host = CameraHostViewController()
|
||||
host.onImageCaptured = { image in
|
||||
onImageCaptured(image)
|
||||
dismiss()
|
||||
}
|
||||
host.onCancel = {
|
||||
dismiss()
|
||||
}
|
||||
host.pickerDelegate = context.coordinator
|
||||
context.coordinator.onImageCaptured = { image in
|
||||
onImageCaptured(image)
|
||||
dismiss()
|
||||
}
|
||||
context.coordinator.onCancel = {
|
||||
dismiss()
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
|
||||
// Nothing here actually... Q_Q
|
||||
func updateUIViewController(_ uiViewController: CameraHostViewController, context: Context) {
|
||||
// No dynamic updates needed
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
Coordinator()
|
||||
}
|
||||
|
||||
class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
|
||||
let parent: CameraImagePicker
|
||||
|
||||
init(_ parent: CameraImagePicker) {
|
||||
self.parent = parent
|
||||
}
|
||||
var onImageCaptured: ((UIImage) -> Void)?
|
||||
var onCancel: (() -> Void)?
|
||||
|
||||
func imagePickerController(
|
||||
_ picker: UIImagePickerController,
|
||||
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
|
||||
) {
|
||||
if let image = info[.originalImage] as? UIImage {
|
||||
parent.onImageCaptured(image)
|
||||
picker.dismiss(animated: true) {
|
||||
if let image = info[.originalImage] as? UIImage {
|
||||
self.onImageCaptured?(image)
|
||||
} else {
|
||||
self.onCancel?()
|
||||
}
|
||||
}
|
||||
parent.isPresented = false
|
||||
}
|
||||
|
||||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
parent.isPresented = false
|
||||
picker.dismiss(animated: true) {
|
||||
self.onCancel?()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extension to check camera availability
|
||||
// MARK: - Hosting VC to own presentation/orientation
|
||||
final class CameraHostViewController: UIViewController {
|
||||
var onImageCaptured: ((UIImage) -> Void)?
|
||||
var onCancel: (() -> Void)?
|
||||
weak var pickerDelegate: (UIImagePickerControllerDelegate & UINavigationControllerDelegate)?
|
||||
|
||||
private var didPresent = false
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
presentIfNeeded()
|
||||
}
|
||||
|
||||
private func presentIfNeeded() {
|
||||
guard !didPresent, UIImagePickerController.isSourceTypeAvailable(.camera) else { return }
|
||||
didPresent = true
|
||||
|
||||
let picker = UIImagePickerController()
|
||||
picker.delegate = pickerDelegate
|
||||
picker.sourceType = .camera
|
||||
picker.cameraCaptureMode = .photo
|
||||
picker.cameraDevice = .rear
|
||||
picker.allowsEditing = false
|
||||
picker.modalPresentationStyle = .fullScreen
|
||||
|
||||
present(picker, animated: true)
|
||||
}
|
||||
|
||||
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||
// Defer to app-supported orientations; returning .all allows rotation when permitted by the app
|
||||
return .all
|
||||
}
|
||||
|
||||
override var shouldAutorotate: Bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Camera Availability Check
|
||||
extension CameraImagePicker {
|
||||
static var isCameraAvailable: Bool {
|
||||
UIImagePickerController.isSourceTypeAvailable(.camera)
|
||||
|
||||
@@ -26,19 +26,19 @@ struct AddAttemptView: View {
|
||||
|
||||
enum SheetType: Identifiable {
|
||||
case photoOptions
|
||||
case camera
|
||||
|
||||
var id: Int {
|
||||
switch self {
|
||||
case .photoOptions: return 0
|
||||
case .camera: return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State private var activeSheet: SheetType?
|
||||
@State private var showCamera = false
|
||||
@State private var showPhotoPicker = false
|
||||
@State private var isPhotoPickerActionPending = false
|
||||
@State private var isCameraActionPending = false
|
||||
|
||||
private var activeProblems: [Problem] {
|
||||
dataManager.activeProblems(forGym: gym.id)
|
||||
@@ -110,6 +110,11 @@ struct AddAttemptView: View {
|
||||
.sheet(
|
||||
item: $activeSheet,
|
||||
onDismiss: {
|
||||
if isCameraActionPending {
|
||||
showCamera = true
|
||||
isCameraActionPending = false
|
||||
return
|
||||
}
|
||||
if isPhotoPickerActionPending {
|
||||
showPhotoPicker = true
|
||||
isPhotoPickerActionPending = false
|
||||
@@ -123,7 +128,8 @@ struct AddAttemptView: View {
|
||||
imageData: $imageData,
|
||||
maxImages: 5,
|
||||
onCameraSelected: {
|
||||
activeSheet = .camera
|
||||
isCameraActionPending = true
|
||||
activeSheet = nil
|
||||
},
|
||||
onPhotoLibrarySelected: {
|
||||
isPhotoPickerActionPending = true
|
||||
@@ -132,16 +138,12 @@ struct AddAttemptView: View {
|
||||
activeSheet = nil
|
||||
}
|
||||
)
|
||||
case .camera:
|
||||
CameraImagePicker(
|
||||
isPresented: Binding(
|
||||
get: { activeSheet == .camera },
|
||||
set: { if !$0 { activeSheet = nil } }
|
||||
)
|
||||
) { capturedImage in
|
||||
if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
|
||||
imageData.append(jpegData)
|
||||
}
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $showCamera) {
|
||||
CameraImagePicker { capturedImage in
|
||||
if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
|
||||
imageData.append(jpegData)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -778,19 +780,19 @@ struct EditAttemptView: View {
|
||||
|
||||
enum SheetType: Identifiable {
|
||||
case photoOptions
|
||||
case camera
|
||||
|
||||
var id: Int {
|
||||
switch self {
|
||||
case .photoOptions: return 0
|
||||
case .camera: return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State private var activeSheet: SheetType?
|
||||
@State private var showCamera = false
|
||||
@State private var showPhotoPicker = false
|
||||
@State private var isPhotoPickerActionPending = false
|
||||
@State private var isCameraActionPending = false
|
||||
|
||||
private var availableProblems: [Problem] {
|
||||
guard let session = dataManager.session(withId: attempt.sessionId) else {
|
||||
@@ -883,6 +885,11 @@ struct EditAttemptView: View {
|
||||
.sheet(
|
||||
item: $activeSheet,
|
||||
onDismiss: {
|
||||
if isCameraActionPending {
|
||||
showCamera = true
|
||||
isCameraActionPending = false
|
||||
return
|
||||
}
|
||||
if isPhotoPickerActionPending {
|
||||
showPhotoPicker = true
|
||||
isPhotoPickerActionPending = false
|
||||
@@ -896,7 +903,8 @@ struct EditAttemptView: View {
|
||||
imageData: $imageData,
|
||||
maxImages: 5,
|
||||
onCameraSelected: {
|
||||
activeSheet = .camera
|
||||
isCameraActionPending = true
|
||||
activeSheet = nil
|
||||
},
|
||||
onPhotoLibrarySelected: {
|
||||
isPhotoPickerActionPending = true
|
||||
@@ -905,16 +913,12 @@ struct EditAttemptView: View {
|
||||
activeSheet = nil
|
||||
}
|
||||
)
|
||||
case .camera:
|
||||
CameraImagePicker(
|
||||
isPresented: Binding(
|
||||
get: { activeSheet == .camera },
|
||||
set: { if !$0 { activeSheet = nil } }
|
||||
)
|
||||
) { capturedImage in
|
||||
if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
|
||||
imageData.append(jpegData)
|
||||
}
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $showCamera) {
|
||||
CameraImagePicker { capturedImage in
|
||||
if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
|
||||
imageData.append(jpegData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,19 +25,19 @@ struct AddEditProblemView: View {
|
||||
@State private var isEditing = false
|
||||
enum SheetType: Identifiable {
|
||||
case photoOptions
|
||||
case camera
|
||||
|
||||
var id: Int {
|
||||
switch self {
|
||||
case .photoOptions: return 0
|
||||
case .camera: return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State private var activeSheet: SheetType?
|
||||
@State private var showCamera = false
|
||||
@State private var showPhotoPicker = false
|
||||
@State private var isPhotoPickerActionPending = false
|
||||
@State private var isCameraActionPending = false
|
||||
|
||||
private var existingProblem: Problem? {
|
||||
guard let problemId = problemId else { return nil }
|
||||
@@ -120,6 +120,11 @@ struct AddEditProblemView: View {
|
||||
.sheet(
|
||||
item: $activeSheet,
|
||||
onDismiss: {
|
||||
if isCameraActionPending {
|
||||
showCamera = true
|
||||
isCameraActionPending = false
|
||||
return
|
||||
}
|
||||
if isPhotoPickerActionPending {
|
||||
showPhotoPicker = true
|
||||
isPhotoPickerActionPending = false
|
||||
@@ -133,7 +138,8 @@ struct AddEditProblemView: View {
|
||||
imageData: $imageData,
|
||||
maxImages: 5,
|
||||
onCameraSelected: {
|
||||
activeSheet = .camera
|
||||
isCameraActionPending = true
|
||||
activeSheet = nil
|
||||
},
|
||||
onPhotoLibrarySelected: {
|
||||
isPhotoPickerActionPending = true
|
||||
@@ -142,16 +148,12 @@ struct AddEditProblemView: View {
|
||||
activeSheet = nil
|
||||
}
|
||||
)
|
||||
case .camera:
|
||||
CameraImagePicker(
|
||||
isPresented: Binding(
|
||||
get: { activeSheet == .camera },
|
||||
set: { if !$0 { activeSheet = nil } }
|
||||
)
|
||||
) { capturedImage in
|
||||
if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
|
||||
imageData.append(jpegData)
|
||||
}
|
||||
}
|
||||
}
|
||||
.fullScreenCover(isPresented: $showCamera) {
|
||||
CameraImagePicker { capturedImage in
|
||||
if let jpegData = capturedImage.jpegData(compressionQuality: 0.8) {
|
||||
imageData.append(jpegData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user