diff --git a/ConversationsClassic/AppData/Model/Chat.swift b/ConversationsClassic/AppData/Model/Chat.swift index 289b983..e3589b1 100644 --- a/ConversationsClassic/AppData/Model/Chat.swift +++ b/ConversationsClassic/AppData/Model/Chat.swift @@ -32,4 +32,12 @@ extension Chat { return roster } } + + func setEncrypted(_ encrypted: Bool) async throws { + try await Database.shared.dbQueue.write { db in + var chat = self + chat.encrypted = encrypted + try chat.update(db) + } + } } diff --git a/ConversationsClassic/AppData/Store/ClientsStore.swift b/ConversationsClassic/AppData/Store/ClientsStore.swift index 6e1f159..8ea544d 100644 --- a/ConversationsClassic/AppData/Store/ClientsStore.swift +++ b/ConversationsClassic/AppData/Store/ClientsStore.swift @@ -122,7 +122,8 @@ extension ClientsStore { // MARK: - Produce stores for conversation extension ClientsStore { - func conversationStores(for roster: Roster) async throws -> (MessagesStore, AttachmentsStore) { + // swiftlint:disable:next large_tuple + func conversationStores(for roster: Roster) async throws -> (MessagesStore, AttachmentsStore, SettingsStore) { while !ready { await Task.yield() } @@ -133,10 +134,12 @@ extension ClientsStore { let conversationStore = MessagesStore(roster: roster, client: client) let attachmentsStore = AttachmentsStore(roster: roster, client: client) - return (conversationStore, attachmentsStore) + let settingsStore = SettingsStore(roster: roster, client: client) + return (conversationStore, attachmentsStore, settingsStore) } - func conversationStores(for chat: Chat) async throws -> (MessagesStore, AttachmentsStore) { + // swiftlint:disable:next large_tuple + func conversationStores(for chat: Chat) async throws -> (MessagesStore, AttachmentsStore, SettingsStore) { while !ready { await Task.yield() } @@ -148,7 +151,8 @@ extension ClientsStore { let roster = try await chat.fetchRoster() let conversationStore = MessagesStore(roster: roster, client: client) let attachmentsStore = AttachmentsStore(roster: roster, client: client) - return (conversationStore, attachmentsStore) + let settingsStore = SettingsStore(roster: roster, client: client) + return (conversationStore, attachmentsStore, settingsStore) } } diff --git a/ConversationsClassic/AppData/Store/SettingsStore.swift b/ConversationsClassic/AppData/Store/SettingsStore.swift new file mode 100644 index 0000000..44b12c8 --- /dev/null +++ b/ConversationsClassic/AppData/Store/SettingsStore.swift @@ -0,0 +1,47 @@ +import Combine +import Foundation +import GRDB +import Photos +import SwiftUI + +@MainActor +final class SettingsStore: ObservableObject { + @Published var chat: Chat? + + private let client: Client + private let roster: Roster + + private var chatCancellable: AnyCancellable? + + init(roster: Roster, client: Client) { + self.client = client + self.roster = roster + + subscribe() + } +} + +extension SettingsStore { + func setSecured(_ secured: Bool) { + Task { + try? await chat?.setEncrypted(secured) + } + } +} + +// MARK: - Processing attachments +private extension SettingsStore { + func subscribe() { + chatCancellable = ValueObservation.tracking(Chat + .filter(Column("bareJid") == roster.bareJid && Column("contactBareJid") == roster.contactBareJid) + .fetchOne + ) + .publisher(in: Database.shared.dbQueue, scheduling: .immediate) + .receive(on: DispatchQueue.main) + .sink { _ in + } receiveValue: { [weak self] chat in + guard let self = self else { return } + self.chat = chat + } + } +} diff --git a/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift b/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift index f0427f8..3679d5d 100644 --- a/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift +++ b/ConversationsClassic/View/Main/ChatList/ChatsListScreen.swift @@ -61,9 +61,9 @@ private struct ChatsRow: View { do { try? await clientsStore.addRosterForNewChatIfNeeded(chat) - let (messages, attachments) = try await clientsStore.conversationStores(for: chat) + let (messages, attachments, settings) = try await clientsStore.conversationStores(for: chat) router.showScreen(.push) { _ in - ConversationScreen(messagesStore: messages, attachments: attachments) + ConversationScreen(messagesStore: messages, attachments: attachments, settings: settings) .navigationBarHidden(true) } } catch { diff --git a/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift b/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift index c5a3f97..1a354bf 100644 --- a/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift +++ b/ConversationsClassic/View/Main/Contacts/ContactsScreen.swift @@ -159,9 +159,9 @@ private struct ContactsScreenRow: View { } do { - let (messages, attachments) = try await clientsStore.conversationStores(for: roster) + let (messages, attachments, settings) = try await clientsStore.conversationStores(for: roster) router.showScreen(.push) { _ in - ConversationScreen(messagesStore: messages, attachments: attachments) + ConversationScreen(messagesStore: messages, attachments: attachments, settings: settings) .navigationBarHidden(true) } } catch { diff --git a/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift b/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift index aa0e7d8..5ec1cd6 100644 --- a/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift +++ b/ConversationsClassic/View/Main/Conversation/ConversationScreen.swift @@ -7,6 +7,7 @@ struct ConversationScreen: View { @Environment(\.router) var router @StateObject var messagesStore: MessagesStore @StateObject var attachments: AttachmentsStore + @StateObject var settings: SettingsStore @State private var autoScroll = true @State private var firstIsVisible = true @@ -30,6 +31,7 @@ struct ConversationScreen: View { centerText: .init(text: centerText(), action: { router.showScreen(.fullScreenCover) { _ in ConversationSettingsScreen() + .environmentObject(settings) } }) ) @@ -108,6 +110,7 @@ struct ConversationScreen: View { ConversationTextInput(autoScroll: $autoScroll) .environmentObject(messagesStore) .environmentObject(attachments) + .environmentObject(settings) } } diff --git a/ConversationsClassic/View/Main/Conversation/ConversationSettingsScreen.swift b/ConversationsClassic/View/Main/Conversation/ConversationSettingsScreen.swift index bee3304..1f8176b 100644 --- a/ConversationsClassic/View/Main/Conversation/ConversationSettingsScreen.swift +++ b/ConversationsClassic/View/Main/Conversation/ConversationSettingsScreen.swift @@ -5,9 +5,7 @@ import SwiftUI struct ConversationSettingsScreen: View { @Environment(\.router) var router - @EnvironmentObject var messagesStore: MessagesStore - - @State private var omemoEnabled = true + @EnvironmentObject var settingsStore: SettingsStore var body: some View { ZStack { @@ -34,7 +32,14 @@ struct ConversationSettingsScreen: View { SharedListRow( iconType: .none, text: L10n.Conversation.Settings.enableOmemo, - controlType: .switcher(isOn: $omemoEnabled) + controlType: .switcher(isOn: Binding( + get: { settingsStore.chat?.encrypted ?? false }, + set: { new in + Task { + try? await settingsStore.chat?.setEncrypted(new) + } + } + )) ) } }