This commit is contained in:
fmodf 2024-08-17 13:22:47 +02:00
parent 0b609bfe93
commit bf040bda25
5 changed files with 135 additions and 149 deletions

View file

@ -1,13 +1,17 @@
import AVFoundation
import Combine import Combine
import Foundation import Foundation
import GRDB import GRDB
import Photos
@MainActor @MainActor
final class ConversationStore: ObservableObject { final class ConversationStore: ObservableObject {
@Published private(set) var messages: [Message] = [] @Published private(set) var messages: [Message] = []
@Published var replyText = "" @Published var replyText = ""
private(set) var roster: Roster @Published var cameraAccessGranted = false
@Published var galleryAccessGranted = false
private(set) var roster: Roster
private let client: Client private let client: Client
private let blockSize = Const.messagesPageSize private let blockSize = Const.messagesPageSize
private let messagesMax = Const.messagesMaxSize private let messagesMax = Const.messagesMaxSize
@ -49,6 +53,27 @@ extension ConversationStore {
} }
} }
extension ConversationStore {
func checkCameraAuthorization() async {
let status = AVCaptureDevice.authorizationStatus(for: .video)
var isAuthorized = status == .authorized
if status == .notDetermined {
isAuthorized = await AVCaptureDevice.requestAccess(for: .video)
}
cameraAccessGranted = isAuthorized
}
func checkGalleryAuthorization() async {
let status = PHPhotoLibrary.authorizationStatus()
var isAuthorized = status == .authorized
if status == .notDetermined {
let req = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
isAuthorized = (req == .authorized) || (req == .limited)
}
galleryAccessGranted = isAuthorized
}
}
private extension ConversationStore { private extension ConversationStore {
func subscribe() { func subscribe() {
messagesCancellable = ValueObservation.tracking(Message messagesCancellable = ValueObservation.tracking(Message
@ -67,26 +92,3 @@ private extension ConversationStore {
} }
} }
} }
// var isAuthorized: Bool {
// get async {
// let status = AVCaptureDevice.authorizationStatus(for: .video)
//
// // Determine if the user previously authorized camera access.
// var isAuthorized = status == .authorized
//
// // If the system hasn't determined the user's authorization status,
// // explicitly prompt them for approval.
// if status == .notDetermined {
// isAuthorized = await AVCaptureDevice.requestAccess(for: .video)
// }
//
// return isAuthorized
// }
// }
//
//
// func setUpCaptureSession() async {
// guard await isAuthorized else { return }
// // Set up the capture session.
// }

View file

@ -3,11 +3,11 @@ import SwiftUI
struct CameraCellPreview: View { struct CameraCellPreview: View {
@Environment(\.router) var router @Environment(\.router) var router
@State private var cameraAuthorized = false @EnvironmentObject var store: ConversationStore
var body: some View { var body: some View {
Group { Group {
if cameraAuthorized { if store.cameraAccessGranted {
ZStack { ZStack {
CameraView() CameraView()
.aspectRatio(1, contentMode: .fit) .aspectRatio(1, contentMode: .fit)
@ -51,16 +51,7 @@ struct CameraCellPreview: View {
} }
} }
.task { .task {
await checkAuthorization() await store.checkCameraAuthorization()
} }
} }
private func checkAuthorization() async {
let status = AVCaptureDevice.authorizationStatus(for: .video)
var isAuthorized = status == .authorized
if status == .notDetermined {
isAuthorized = await AVCaptureDevice.requestAccess(for: .video)
}
cameraAuthorized = isAuthorized
}
} }

View file

@ -0,0 +1,104 @@
import SwiftUI
struct GalleryView: View {
// @State private var selectedItems: [String] = []
var body: some View {
Text("test")
// Group {
// if store.state.sharingState.isGalleryAccessGranted {
// ForEach(store.state.sharingState.galleryItems) { item in
// GridViewItem(item: item, selected: $selectedItems)
// }
// } else {
// Button {
// openAppSettings()
// } label: {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// VStack {
// Image(systemName: "photo")
// .foregroundColor(.Material.Elements.active)
// .font(.system(size: 30))
// Text("Allow gallery access")
// .foregroundColor(.Material.Text.main)
// .font(.body3)
// }
// }
// .frame(height: 100)
// }
// }
// }
// }
}
}
private struct GridViewItem: View {
// let item: SharingGalleryItem
@Binding var selected: [String]
@State var isSelected = false
var body: some View {
Text("Test")
// if let data = item.thumbnail {
// ZStack {
// Image(uiImage: UIImage(data: data) ?? UIImage())
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: Const.galleryGridSize, height: Const.galleryGridSize)
// .clipped()
// if let duration = item.duration {
// VStack {
// Spacer()
// HStack {
// Spacer()
// Text(duration)
// .foregroundColor(.Material.Text.white)
// .font(.sub1)
// .shadow(color: .black, radius: 2)
// .padding(4)
// }
// }
// }
// if isSelected {
// VStack {
// HStack {
// Spacer()
// Circle()
// .frame(width: 30, height: 30)
// .shadow(color: .black, radius: 2)
// .foregroundColor(.Material.Shape.white)
// .overlay {
// Image(systemName: "checkmark")
// .foregroundColor(.Material.Elements.active)
// .font(.body3)
// }
// .padding(4)
// }
// Spacer()
// }
// }
// }
// .onTapGesture {
// isSelected.toggle()
// if isSelected {
// selected.append(item.id)
// } else {
// selected.removeAll { $0 == item.id }
// }
// }
// } else {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// ProgressView()
// .foregroundColor(.Material.Elements.active)
// }
// .frame(width: Const.galleryGridSize, height: Const.galleryGridSize)
// }
// }
}
}

View file

@ -4,9 +4,6 @@ import Photos
import SwiftUI import SwiftUI
struct MediaPickerView: View { struct MediaPickerView: View {
// @State private var showCameraPicker = false
// @State private var cameraReady = false
@State private var selectedItems: [String] = [] @State private var selectedItems: [String] = []
var body: some View { var body: some View {
@ -20,41 +17,9 @@ struct MediaPickerView: View {
CameraCellPreview() CameraCellPreview()
// For gallery // For gallery
// if store.state.sharingState.isGalleryAccessGranted { GalleryView()
// ForEach(store.state.sharingState.galleryItems) { item in
// GridViewItem(item: item, selected: $selectedItems)
// }
// } else {
// Button {
// openAppSettings()
// } label: {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// VStack {
// Image(systemName: "photo")
// .foregroundColor(.Material.Elements.active)
// .font(.system(size: 30))
// Text("Allow gallery access")
// .foregroundColor(.Material.Text.main)
// .font(.body3)
// }
// }
// .frame(height: 100)
// }
// }
// }
} }
} }
// .fullScreenCover(isPresented: $showCameraPicker) {
// CameraPicker(sourceType: .camera) { data, type in
// store.dispatch(.sharingAction(.cameraCaptured(media: data, type: type)))
// showCameraPicker = false
// store.dispatch(.sharingAction(.showSharing(false)))
// }
// .edgesIgnoringSafeArea(.all)
// }
// Send panel // Send panel
Rectangle() Rectangle()
@ -79,82 +44,5 @@ struct MediaPickerView: View {
// store.dispatch(.sharingAction(.showSharing(false))) // store.dispatch(.sharingAction(.showSharing(false)))
} }
} }
// .onAppear {
// store.dispatch(.sharingAction(.checkCameraAccess))
// store.dispatch(.sharingAction(.checkGalleryAccess))
// }
// .onChange(of: store.state.sharingState.isGalleryAccessGranted) { granted in
// if granted {
// store.dispatch(.fileAction(.fetchItemsFromGallery))
// }
// }
}
}
private struct GridViewItem: View {
// let item: SharingGalleryItem
@Binding var selected: [String]
@State var isSelected = false
var body: some View {
Text("Test")
// if let data = item.thumbnail {
// ZStack {
// Image(uiImage: UIImage(data: data) ?? UIImage())
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: Const.galleryGridSize, height: Const.galleryGridSize)
// .clipped()
// if let duration = item.duration {
// VStack {
// Spacer()
// HStack {
// Spacer()
// Text(duration)
// .foregroundColor(.Material.Text.white)
// .font(.sub1)
// .shadow(color: .black, radius: 2)
// .padding(4)
// }
// }
// }
// if isSelected {
// VStack {
// HStack {
// Spacer()
// Circle()
// .frame(width: 30, height: 30)
// .shadow(color: .black, radius: 2)
// .foregroundColor(.Material.Shape.white)
// .overlay {
// Image(systemName: "checkmark")
// .foregroundColor(.Material.Elements.active)
// .font(.body3)
// }
// .padding(4)
// }
// Spacer()
// }
// }
// }
// .onTapGesture {
// isSelected.toggle()
// if isSelected {
// selected.append(item.id)
// } else {
// selected.removeAll { $0 == item.id }
// }
// }
// } else {
// ZStack {
// Rectangle()
// .fill(Color.Material.Background.light)
// .overlay {
// ProgressView()
// .foregroundColor(.Material.Elements.active)
// }
// .frame(width: Const.galleryGridSize, height: Const.galleryGridSize)
// }
// }
} }
} }

View file

@ -52,6 +52,7 @@ struct ConversationTextInput: View {
.tappablePadding(.symmetric(8)) { .tappablePadding(.symmetric(8)) {
router.showScreen(.fullScreenCover) { _ in router.showScreen(.fullScreenCover) { _ in
AttachmentPickerScreen() AttachmentPickerScreen()
.environmentObject(conversation)
} }
} }
TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator)) TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator))