mv-experiment #1
|
@ -9,9 +9,11 @@ final class ClientsStore: ObservableObject {
|
||||||
@Published private(set) var ready = false
|
@Published private(set) var ready = false
|
||||||
@Published private(set) var clients: [Client] = []
|
@Published private(set) var clients: [Client] = []
|
||||||
@Published private(set) var actualRosters: [Roster] = []
|
@Published private(set) var actualRosters: [Roster] = []
|
||||||
|
@Published private(set) var actualChats: [Chat] = []
|
||||||
|
|
||||||
private var credentialsCancellable: AnyCancellable?
|
private var credentialsCancellable: AnyCancellable?
|
||||||
private var rostersCancellable: AnyCancellable?
|
private var rostersCancellable: AnyCancellable?
|
||||||
|
private var chatsCancellable: AnyCancellable?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
credentialsCancellable = ValueObservation
|
credentialsCancellable = ValueObservation
|
||||||
|
@ -44,6 +46,8 @@ final class ClientsStore: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
resubscribeRosters()
|
resubscribeRosters()
|
||||||
|
resubscribeChats()
|
||||||
|
reconnectAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func client(for credentials: Credentials) -> Client? {
|
private func client(for credentials: Credentials) -> Client? {
|
||||||
|
@ -62,7 +66,7 @@ extension ClientsStore {
|
||||||
try? await client.credentials.save()
|
try? await client.credentials.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
func reconnectAll() {
|
private func reconnectAll() {
|
||||||
Task {
|
Task {
|
||||||
await withTaskGroup(of: Void.self) { taskGroup in
|
await withTaskGroup(of: Void.self) { taskGroup in
|
||||||
for client in clients {
|
for client in clients {
|
||||||
|
@ -116,3 +120,22 @@ extension ClientsStore {
|
||||||
try await client.deleteRoster(roster)
|
try await client.deleteRoster(roster)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ClientsStore {
|
||||||
|
private func resubscribeChats() {
|
||||||
|
let clientsJids = clients
|
||||||
|
.filter { $0.state != .disabled }
|
||||||
|
.map { $0.credentials.bareJid }
|
||||||
|
|
||||||
|
chatsCancellable = ValueObservation.tracking { db in
|
||||||
|
try Chat
|
||||||
|
.filter(clientsJids.contains(Column("account")))
|
||||||
|
.fetchAll(db)
|
||||||
|
}
|
||||||
|
.publisher(in: Database.shared.dbQueue)
|
||||||
|
.catch { _ in Just([]) }
|
||||||
|
.sink { [weak self] chats in
|
||||||
|
self?.actualChats = chats
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
"Contacts.Delete.message" = "You can delete contact from this device (contact will be available on other devices), or delete it completely";
|
"Contacts.Delete.message" = "You can delete contact from this device (contact will be available on other devices), or delete it completely";
|
||||||
"Contacts.Delete.error" = "Contact not deleted. Server returns error.";
|
"Contacts.Delete.error" = "Contact not deleted. Server returns error.";
|
||||||
|
|
||||||
|
// MARK: Chats list screen
|
||||||
|
"ChatsList.title" = "Chats";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,10 +50,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Chats screen
|
|
||||||
//"Chats.title" = "Chats";
|
|
||||||
|
|
||||||
//"Chat.title" = "Chat";
|
|
||||||
//"Chat.textfieldPrompt" = "Type a message";
|
//"Chat.textfieldPrompt" = "Type a message";
|
||||||
|
|
||||||
//"Chats.Create.Main.title" = "Create";
|
//"Chats.Create.Main.title" = "Create";
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ChatsListScreen: View {
|
||||||
|
@EnvironmentObject var clientsStore: ClientsStore
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
// Background color
|
||||||
|
Color.Material.Background.light
|
||||||
|
.ignoresSafeArea()
|
||||||
|
|
||||||
|
// Content
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
// Header
|
||||||
|
SharedNavigationBar(
|
||||||
|
centerText: .init(text: L10n.ChatsList.title),
|
||||||
|
rightButton: .init(
|
||||||
|
image: Image(systemName: "square.and.pencil"),
|
||||||
|
action: {
|
||||||
|
// isCretePanelPresented = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Chats list
|
||||||
|
if !clientsStore.actualChats.isEmpty {
|
||||||
|
List {
|
||||||
|
ForEach(clientsStore.actualChats) { chat in
|
||||||
|
ChatsRow(chat: chat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listStyle(.plain)
|
||||||
|
.background(Color.Material.Background.light)
|
||||||
|
} else {
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// .fullScreenCover(isPresented: $isCretePanelPresented) {
|
||||||
|
// ChatsCreateMainScreen(isPresented: $isCretePanelPresented)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ChatsRow: View {
|
||||||
|
// @EnvironmentObject var store: AppStore
|
||||||
|
|
||||||
|
var chat: Chat
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
SharedListRow(iconType: .charCircle(chat.participant), text: chat.participant)
|
||||||
|
.onTapGesture {
|
||||||
|
// store.dispatch(.chatsAction(.startChat(accountJid: chat.account, participantJid: chat.participant)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ import SwiftfulRouting
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
private enum Tab {
|
private enum Tab {
|
||||||
case conversations
|
case chats
|
||||||
case contacts
|
case contacts
|
||||||
case settings
|
case settings
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ private enum Tab {
|
||||||
struct MainTabScreen: View {
|
struct MainTabScreen: View {
|
||||||
@EnvironmentObject var clientsStore: ClientsStore
|
@EnvironmentObject var clientsStore: ClientsStore
|
||||||
|
|
||||||
@State private var selectedTab: Tab = .conversations
|
@State private var selectedTab: Tab = .chats
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
@ -22,9 +22,8 @@ struct MainTabScreen: View {
|
||||||
// Content
|
// Content
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
switch selectedTab {
|
switch selectedTab {
|
||||||
case .conversations:
|
case .chats:
|
||||||
Color.red
|
ChatsListScreen()
|
||||||
// ConversationsScreen()
|
|
||||||
|
|
||||||
case .contacts:
|
case .contacts:
|
||||||
ContactsScreen()
|
ContactsScreen()
|
||||||
|
@ -38,9 +37,6 @@ struct MainTabScreen: View {
|
||||||
TabBar(selectedTab: $selectedTab)
|
TabBar(selectedTab: $selectedTab)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onLoad {
|
|
||||||
clientsStore.reconnectAll()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +51,7 @@ private struct TabBar: View {
|
||||||
.foregroundColor(.Material.Shape.separator)
|
.foregroundColor(.Material.Shape.separator)
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
TabBarButton(buttonType: .contacts, selectedTab: $selectedTab)
|
TabBarButton(buttonType: .contacts, selectedTab: $selectedTab)
|
||||||
TabBarButton(buttonType: .conversations, selectedTab: $selectedTab)
|
TabBarButton(buttonType: .chats, selectedTab: $selectedTab)
|
||||||
TabBarButton(buttonType: .settings, selectedTab: $selectedTab)
|
TabBarButton(buttonType: .settings, selectedTab: $selectedTab)
|
||||||
}
|
}
|
||||||
.background(Color.Material.Background.dark)
|
.background(Color.Material.Background.dark)
|
||||||
|
@ -93,7 +89,7 @@ private struct TabBarButton: View {
|
||||||
case .contacts:
|
case .contacts:
|
||||||
return Image(systemName: "person.2.fill")
|
return Image(systemName: "person.2.fill")
|
||||||
|
|
||||||
case .conversations:
|
case .chats:
|
||||||
return Image(systemName: "bubble.left.fill")
|
return Image(systemName: "bubble.left.fill")
|
||||||
|
|
||||||
case .settings:
|
case .settings:
|
||||||
|
@ -106,7 +102,7 @@ private struct TabBarButton: View {
|
||||||
case .contacts:
|
case .contacts:
|
||||||
return L10n.Tabs.Name.contacts
|
return L10n.Tabs.Name.contacts
|
||||||
|
|
||||||
case .conversations:
|
case .chats:
|
||||||
return L10n.Tabs.Name.conversations
|
return L10n.Tabs.Name.conversations
|
||||||
|
|
||||||
case .settings:
|
case .settings:
|
||||||
|
|
Loading…
Reference in a new issue