mv-experiment #1
|
@ -141,7 +141,7 @@ extension ClientsStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ClientsStore {
|
extension ClientsStore {
|
||||||
func conversationStore(for roster: Roster) async throws -> ConversationStore {
|
func getStores(for roster: Roster) async throws -> (ConversationStore, FileStore) {
|
||||||
while !ready {
|
while !ready {
|
||||||
await Task.yield()
|
await Task.yield()
|
||||||
}
|
}
|
||||||
|
@ -150,10 +150,13 @@ extension ClientsStore {
|
||||||
throw ClientStoreError.clientNotFound
|
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 {
|
while !ready {
|
||||||
await Task.yield()
|
await Task.yield()
|
||||||
}
|
}
|
||||||
|
@ -163,6 +166,9 @@ extension ClientsStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
let roster = try await chat.fetchRoster()
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ import Photos
|
||||||
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 = ""
|
||||||
@Published var cameraAccessGranted = false
|
|
||||||
@Published var galleryAccessGranted = false
|
|
||||||
|
|
||||||
private(set) var roster: Roster
|
private(set) var roster: Roster
|
||||||
private let client: Client
|
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 {
|
private extension ConversationStore {
|
||||||
func subscribe() {
|
func subscribe() {
|
||||||
messagesCancellable = ValueObservation.tracking(Message
|
messagesCancellable = ValueObservation.tracking(Message
|
||||||
|
|
38
ConversationsClassic/AppData/Store/FileStore.swift
Normal file
38
ConversationsClassic/AppData/Store/FileStore.swift
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,9 +60,9 @@ private struct ChatsRow: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let conversation = try await clientsStore.conversationStore(for: chat)
|
let (conversation, fileStore) = try await clientsStore.getStores(for: chat)
|
||||||
router.showScreen(.push) { _ in
|
router.showScreen(.push) { _ in
|
||||||
ConversationScreen(conversation: conversation)
|
ConversationScreen(conversation: conversation, fileStore: fileStore)
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -158,9 +158,9 @@ private struct ContactsScreenRow: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let conversation = try await clientsStore.conversationStore(for: roster)
|
let (conversation, fileStore) = try await clientsStore.getStores(for: roster)
|
||||||
router.showScreen(.push) { _ in
|
router.showScreen(.push) { _ in
|
||||||
ConversationScreen(conversation: conversation)
|
ConversationScreen(conversation: conversation, fileStore: fileStore)
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import SwiftUI
|
||||||
|
|
||||||
struct CameraCellPreview: View {
|
struct CameraCellPreview: View {
|
||||||
@Environment(\.router) var router
|
@Environment(\.router) var router
|
||||||
@EnvironmentObject var store: ConversationStore
|
@EnvironmentObject var store: FileStore
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import SwiftUI
|
||||||
struct ConversationScreen: View {
|
struct ConversationScreen: View {
|
||||||
@Environment(\.router) var router
|
@Environment(\.router) var router
|
||||||
@StateObject var conversation: ConversationStore
|
@StateObject var conversation: ConversationStore
|
||||||
|
@StateObject var fileStore: FileStore
|
||||||
|
|
||||||
@State private var autoScroll = true
|
@State private var autoScroll = true
|
||||||
@State private var firstIsVisible = true
|
@State private var firstIsVisible = true
|
||||||
|
@ -101,6 +102,7 @@ struct ConversationScreen: View {
|
||||||
.safeAreaInset(edge: .bottom, spacing: 0) {
|
.safeAreaInset(edge: .bottom, spacing: 0) {
|
||||||
ConversationTextInput(autoScroll: $autoScroll)
|
ConversationTextInput(autoScroll: $autoScroll)
|
||||||
.environmentObject(conversation)
|
.environmentObject(conversation)
|
||||||
|
.environmentObject(fileStore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import UIKit
|
||||||
struct ConversationTextInput: View {
|
struct ConversationTextInput: View {
|
||||||
@Environment(\.router) var router
|
@Environment(\.router) var router
|
||||||
@EnvironmentObject var conversation: ConversationStore
|
@EnvironmentObject var conversation: ConversationStore
|
||||||
|
@EnvironmentObject var fileStore: FileStore
|
||||||
|
|
||||||
@State private var messageStr = ""
|
@State private var messageStr = ""
|
||||||
@FocusState private var isFocused: Bool
|
@FocusState private var isFocused: Bool
|
||||||
|
@ -53,6 +54,7 @@ struct ConversationTextInput: View {
|
||||||
router.showScreen(.fullScreenCover) { _ in
|
router.showScreen(.fullScreenCover) { _ in
|
||||||
AttachmentPickerScreen()
|
AttachmentPickerScreen()
|
||||||
.environmentObject(conversation)
|
.environmentObject(conversation)
|
||||||
|
.environmentObject(fileStore)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator))
|
TextField("", text: $messageStr, prompt: Text(L10n.Chat.textfieldPrompt).foregroundColor(.Material.Shape.separator))
|
||||||
|
|
Loading…
Reference in a new issue