diff --git a/ConversationsClassic/AppData/Store/ClientsStore.swift b/ConversationsClassic/AppData/Store/ClientsStore.swift index e39118b..0ed4460 100644 --- a/ConversationsClassic/AppData/Store/ClientsStore.swift +++ b/ConversationsClassic/AppData/Store/ClientsStore.swift @@ -141,7 +141,7 @@ extension ClientsStore { } extension ClientsStore { - func conversationStore(for roster: Roster) async throws -> ConversationStore { + func getStores(for roster: Roster) async throws -> (ConversationStore, FileStore) { while !ready { await Task.yield() } @@ -150,10 +150,13 @@ extension ClientsStore { throw ClientStoreError.clientNotFound } - return ConversationStore(roster: roster, client: client) + let conversation = ConversationStore(roster: roster, client: client) + let fileStore = FileStore(roster: roster, client: client) + + return (conversation, fileStore) } - func conversationStore(for chat: Chat) async throws -> ConversationStore { + func getStores(for chat: Chat) async throws -> (ConversationStore, FileStore) { while !ready { await Task.yield() } @@ -163,6 +166,9 @@ extension ClientsStore { } let roster = try await chat.fetchRoster() - return ConversationStore(roster: roster, client: client) + let conversation = ConversationStore(roster: roster, client: client) + let fileStore = FileStore(roster: roster, client: client) + + return (conversation, fileStore) } } diff --git a/ConversationsClassic/AppData/Store/ConversationStore.swift b/ConversationsClassic/AppData/Store/ConversationStore.swift index 592f328..b008026 100644 --- a/ConversationsClassic/AppData/Store/ConversationStore.swift +++ b/ConversationsClassic/AppData/Store/ConversationStore.swift @@ -8,8 +8,6 @@ import Photos final class ConversationStore: ObservableObject { @Published private(set) var messages: [Message] = [] @Published var replyText = "" - @Published var cameraAccessGranted = false - @Published var galleryAccessGranted = false private(set) var roster: Roster private let client: Client @@ -53,27 +51,6 @@ 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 { func subscribe() { messagesCancellable = ValueObservation.tracking(Message diff --git a/ConversationsClassic/AppData/Store/FileStore.swift b/ConversationsClassic/AppData/Store/FileStore.swift new file mode 100644 index 0000000..61ad3a3 --- /dev/null +++ b/ConversationsClassic/AppData/Store/FileStore.swift @@ -0,0 +1,38 @@ +import Combine +import Foundation +import Photos + +@MainActor +final class FileStore: ObservableObject { + @Published var cameraAccessGranted = false + @Published var galleryAccessGranted = false + + private let client: Client + private let roster: Roster + + init(roster: Roster, client: Client) { + self.client = client + self.roster = roster + } +} + +extension FileStore { + 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 + } +} diff --git a/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift b/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift index 4533f6c..4e22761 100644 --- a/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift +++ b/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift @@ -60,9 +60,9 @@ private struct ChatsRow: View { } do { - let conversation = try await clientsStore.conversationStore(for: chat) + let (conversation, fileStore) = try await clientsStore.getStores(for: chat) router.showScreen(.push) { _ in - ConversationScreen(conversation: conversation) + ConversationScreen(conversation: conversation, fileStore: fileStore) .navigationBarHidden(true) } } catch { diff --git a/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift b/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift index aafaf22..4427804 100644 --- a/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift +++ b/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift @@ -158,9 +158,9 @@ private struct ContactsScreenRow: View { } do { - let conversation = try await clientsStore.conversationStore(for: roster) + let (conversation, fileStore) = try await clientsStore.getStores(for: roster) router.showScreen(.push) { _ in - ConversationScreen(conversation: conversation) + ConversationScreen(conversation: conversation, fileStore: fileStore) .navigationBarHidden(true) } } catch { diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift index 65cf60c..73b348f 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/MediaPicker/CameraCellPreview.swift @@ -3,7 +3,7 @@ import SwiftUI struct CameraCellPreview: View { @Environment(\.router) var router - @EnvironmentObject var store: ConversationStore + @EnvironmentObject var store: FileStore var body: some View { Group { diff --git a/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift b/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift index 88cb70b..edfeb86 100644 --- a/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift +++ b/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift @@ -6,6 +6,7 @@ import SwiftUI struct ConversationScreen: View { @Environment(\.router) var router @StateObject var conversation: ConversationStore + @StateObject var fileStore: FileStore @State private var autoScroll = true @State private var firstIsVisible = true @@ -101,6 +102,7 @@ struct ConversationScreen: View { .safeAreaInset(edge: .bottom, spacing: 0) { ConversationTextInput(autoScroll: $autoScroll) .environmentObject(conversation) + .environmentObject(fileStore) } } } diff --git a/ConversationsClassic/View/Main/Conversation/ConversationTextInput.swift b/ConversationsClassic/View/Main/Conversation/ConversationTextInput.swift index f02be43..cc07667 100644 --- a/ConversationsClassic/View/Main/Conversation/ConversationTextInput.swift +++ b/ConversationsClassic/View/Main/Conversation/ConversationTextInput.swift @@ -4,6 +4,7 @@ import UIKit struct ConversationTextInput: View { @Environment(\.router) var router @EnvironmentObject var conversation: ConversationStore + @EnvironmentObject var fileStore: FileStore @State private var messageStr = "" @FocusState private var isFocused: Bool @@ -53,6 +54,7 @@ struct ConversationTextInput: View { router.showScreen(.fullScreenCover) { _ in AttachmentPickerScreen() .environmentObject(conversation) + .environmentObject(fileStore) } } TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator))