wip
This commit is contained in:
parent
b98bcbcfad
commit
d0c45cd41d
|
@ -4,14 +4,19 @@ import Foundation
|
|||
@MainActor
|
||||
final class NavigationStore: ObservableObject {
|
||||
enum Flow: Equatable {
|
||||
enum Entering {
|
||||
enum Entering: Equatable {
|
||||
case welcome
|
||||
case login
|
||||
case registration
|
||||
}
|
||||
|
||||
enum Main {
|
||||
case contacts
|
||||
enum Main: Equatable {
|
||||
enum Contacts: Equatable {
|
||||
case list
|
||||
case add
|
||||
}
|
||||
|
||||
case contacts(Contacts)
|
||||
case conversations
|
||||
case settings
|
||||
}
|
||||
|
|
|
@ -7,10 +7,15 @@ struct ConversationsClassic: App {
|
|||
private var clientsStore = ClientsStore()
|
||||
private var navigationStore = NavigationStore()
|
||||
|
||||
init() {
|
||||
// There's a bug on iOS 17 where sheet may not load with large title, even if modifiers are set, which causes some tests to fail
|
||||
// https://stackoverflow.com/questions/77253122/swiftui-navigationstack-title-loads-inline-instead-of-large-when-sheet-is-pres
|
||||
UINavigationBar.appearance().prefersLargeTitles = true
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
AppRootView()
|
||||
.environmentObject(navigationStore)
|
||||
.environmentObject(clientsStore)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ struct AppRootView: View {
|
|||
case .start:
|
||||
StartScreen()
|
||||
|
||||
case .entering(let entering):
|
||||
switch entering {
|
||||
case .entering(let kind):
|
||||
switch kind {
|
||||
case .welcome:
|
||||
WelcomeScreen()
|
||||
|
||||
|
@ -23,8 +23,17 @@ struct AppRootView: View {
|
|||
|
||||
case .main(let main):
|
||||
switch main {
|
||||
case .contacts:
|
||||
ContactsScreen()
|
||||
case .contacts(let kind):
|
||||
switch kind {
|
||||
case .list:
|
||||
ContactsScreen()
|
||||
|
||||
case .add:
|
||||
ContactsScreen()
|
||||
.fullScreenCover(isPresented: .constant(true)) {
|
||||
AddContactOrChannelScreen()
|
||||
}
|
||||
}
|
||||
|
||||
case .conversations:
|
||||
EmptyView()
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
import SwiftUI
|
||||
|
||||
struct AddContactOrChannelScreen: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
// @EnvironmentObject var store: AppStore
|
||||
|
||||
// enum Field {
|
||||
// case account
|
||||
// case contact
|
||||
// }
|
||||
//
|
||||
// @FocusState private var focus: Field?
|
||||
//
|
||||
// @Binding var isPresented: Bool
|
||||
// @State private var contactJID: String = ""
|
||||
// // @State private var ownerAccount: Account?
|
||||
//
|
||||
// @State private var isShowingLoader = false
|
||||
// @State private var isShowingAlert = false
|
||||
// @State private var errorMsg = ""
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Background color
|
||||
Color.Material.Background.light
|
||||
.ignoresSafeArea()
|
||||
|
||||
// Content
|
||||
VStack(spacing: 0) {
|
||||
// Header
|
||||
SharedNavigationBar(
|
||||
leftButton: .init(
|
||||
image: Image(systemName: "xmark"),
|
||||
action: {
|
||||
withAnimation {
|
||||
navigation.flow = .main(.contacts(.list))
|
||||
}
|
||||
// isPresented = false
|
||||
}
|
||||
),
|
||||
centerText: .init(text: L10n.Contacts.Add.title),
|
||||
rightButton: .init(
|
||||
image: Image(systemName: "plus.viewfinder"),
|
||||
action: {
|
||||
print("Scan QR-code")
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// VStack(spacing: 16) {
|
||||
// // Explanation text
|
||||
//
|
||||
// Text(L10n.Contacts.Add.explanation)
|
||||
// .font(.body3)
|
||||
// .foregroundColor(.Material.Shape.separator)
|
||||
// .multilineTextAlignment(.center)
|
||||
// .padding(.top, 16)
|
||||
//
|
||||
// // Account selector
|
||||
// HStack(spacing: 0) {
|
||||
// Text("Use account:")
|
||||
// .font(.body2)
|
||||
// .foregroundColor(.Material.Text.main)
|
||||
// .frame(alignment: .leading)
|
||||
// Spacer()
|
||||
// }
|
||||
// // UniversalInputCollection.DropDownMenu(
|
||||
// // prompt: "Use account",
|
||||
// // elements: store.state.accountsState.accounts,
|
||||
// // selected: $ownerAccount,
|
||||
// // focus: $focus,
|
||||
// // fieldType: .account
|
||||
// // )
|
||||
//
|
||||
// // Contact text input
|
||||
// HStack(spacing: 0) {
|
||||
// Text("Contact JID:")
|
||||
// .font(.body2)
|
||||
// .foregroundColor(.Material.Text.main)
|
||||
// .frame(alignment: .leading)
|
||||
// Spacer()
|
||||
// }
|
||||
// UniversalInputCollection.TextField(
|
||||
// prompt: "Contact or channel JID",
|
||||
// text: $contactJID,
|
||||
// focus: $focus,
|
||||
// fieldType: .contact,
|
||||
// contentType: .emailAddress,
|
||||
// keyboardType: .emailAddress,
|
||||
// submitLabel: .done,
|
||||
// action: {
|
||||
// focus = .account
|
||||
// }
|
||||
// )
|
||||
//
|
||||
// // Save button
|
||||
// Button {
|
||||
// navigation.flow = .main(.contacts(.list))
|
||||
// } label: {
|
||||
// Text(L10n.Global.save)
|
||||
// }
|
||||
// .buttonStyle(PrimaryButtonStyle())
|
||||
// .disabled(!inputValid)
|
||||
// .padding(.top)
|
||||
// Spacer()
|
||||
// }
|
||||
.padding(.horizontal, 32)
|
||||
}
|
||||
}
|
||||
// .onAppear {
|
||||
// if let exists = store.state.accountsState.accounts.first, exists.isActive {
|
||||
// ownerAccount = exists
|
||||
// }
|
||||
// }
|
||||
// .loadingIndicator(isShowingLoader)
|
||||
// .alert(isPresented: $isShowingAlert) {
|
||||
// Alert(
|
||||
// title: Text(L10n.Global.Error.title),
|
||||
// message: Text(errorMsg),
|
||||
// dismissButton: .default(Text(L10n.Global.ok))
|
||||
// )
|
||||
// }
|
||||
// .onChange(of: store.state.rostersState.newAddedRosterJid) { jid in
|
||||
// if jid != nil, isShowingLoader {
|
||||
// isShowingLoader = false
|
||||
// isPresented = false
|
||||
// }
|
||||
// }
|
||||
// .onChange(of: store.state.rostersState.newAddedRosterError) { error in
|
||||
// if let error = error, isShowingLoader {
|
||||
// isShowingLoader = false
|
||||
// errorMsg = error
|
||||
// isShowingAlert = true
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private var inputValid: Bool {
|
||||
true
|
||||
// ownerAccount != nil && !contactJID.isEmpty && UniversalInputCollection.Validators.isEmail(contactJID)
|
||||
}
|
||||
|
||||
// private func save() {
|
||||
// guard let ownerAccount else { return }
|
||||
// if let exists = store.state.rostersState.rosters.first(where: { $0.bareJid == ownerAccount.bareJid && $0.contactBareJid == contactJID }), exists.locallyDeleted {
|
||||
// store.dispatch(.rostersAction(.unmarkRosterAsLocallyDeleted(ownerJID: ownerAccount.bareJid, contactJID: contactJID)))
|
||||
// isPresented = false
|
||||
// } else {
|
||||
// isShowingLoader = true
|
||||
// store.dispatch(.rostersAction(.addRoster(ownerJID: ownerAccount.bareJid, contactJID: contactJID, name: nil, groups: [])))
|
||||
// }
|
||||
// }
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import SwiftUI
|
||||
|
||||
struct ContactsScreen: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
@EnvironmentObject var clientsStore: ClientsStore
|
||||
@StateObject var rostersStore = RostersStore(clientsPublisher: ClientsStore.shared.$clients)
|
||||
// @State private var addPanelPresented = false
|
||||
|
@ -8,8 +9,6 @@ struct ContactsScreen: View {
|
|||
// @State private var errorAlertMessage = ""
|
||||
// @State private var isShowingLoader = false
|
||||
|
||||
@State private var rosters: [Roster] = []
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Background color
|
||||
|
@ -24,15 +23,18 @@ struct ContactsScreen: View {
|
|||
rightButton: .init(
|
||||
image: Image(systemName: "plus"),
|
||||
action: {
|
||||
withAnimation {
|
||||
navigation.flow = .main(.contacts(.add))
|
||||
}
|
||||
// addPanelPresented = true
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// Contacts list
|
||||
if !rosters.isEmpty {
|
||||
if !rostersStore.rosters.isEmpty {
|
||||
List {
|
||||
ForEach(rosters) { roster in
|
||||
ForEach(rostersStore.rosters) { roster in
|
||||
ContactsScreenRow(
|
||||
roster: roster
|
||||
// isErrorAlertPresented: $isErrorAlertPresented,
|
||||
|
@ -51,9 +53,9 @@ struct ContactsScreen: View {
|
|||
SharedTabBar()
|
||||
}
|
||||
}
|
||||
.task {
|
||||
await fetchRosters()
|
||||
}
|
||||
// .task {
|
||||
// await fetchRosters()
|
||||
// }
|
||||
// .loadingIndicator(isShowingLoader)
|
||||
// .fullScreenCover(isPresented: $addPanelPresented) {
|
||||
// AddContactOrChannelScreen(isPresented: $addPanelPresented)
|
||||
|
@ -67,27 +69,27 @@ struct ContactsScreen: View {
|
|||
// }
|
||||
}
|
||||
|
||||
private func fetchRosters() async {
|
||||
let jids = clientsStore.clients
|
||||
.filter { $0.state != .disabled }
|
||||
.map { $0.credentials.bareJid }
|
||||
|
||||
do {
|
||||
try await withThrowingTaskGroup(of: [Roster].self) { group in
|
||||
for jid in jids {
|
||||
group.addTask {
|
||||
try await Roster.fetchAll(for: jid)
|
||||
}
|
||||
}
|
||||
|
||||
var allRosters: [Roster] = []
|
||||
for try await rosters in group {
|
||||
allRosters.append(contentsOf: rosters)
|
||||
}
|
||||
self.rosters = allRosters.sorted { $0.contactBareJid < $1.contactBareJid }
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
// private func fetchRosters() async {
|
||||
// let jids = clientsStore.clients
|
||||
// .filter { $0.state != .disabled }
|
||||
// .map { $0.credentials.bareJid }
|
||||
//
|
||||
// do {
|
||||
// try await withThrowingTaskGroup(of: [Roster].self) { group in
|
||||
// for jid in jids {
|
||||
// group.addTask {
|
||||
// try await Roster.fetchAll(for: jid)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// var allRosters: [Roster] = []
|
||||
// for try await rosters in group {
|
||||
// allRosters.append(contentsOf: rosters)
|
||||
// }
|
||||
// self.rosters = allRosters.sorted { $0.contactBareJid < $1.contactBareJid }
|
||||
// }
|
||||
// } catch {}
|
||||
// }
|
||||
}
|
||||
|
||||
private struct ContactsScreenRow: View {
|
||||
|
|
|
@ -130,7 +130,7 @@ struct LoginScreen: View {
|
|||
isLoading = false
|
||||
isError = false
|
||||
if navigation.flow == .entering(.login) {
|
||||
navigation.flow = .main(.contacts)
|
||||
navigation.flow = .main(.contacts(.list))
|
||||
}
|
||||
|
||||
case .failure:
|
||||
|
|
|
@ -8,7 +8,7 @@ struct SharedTabBar: View {
|
|||
.frame(height: 0.2)
|
||||
.foregroundColor(.Material.Shape.separator)
|
||||
HStack(spacing: 0) {
|
||||
SharedTabBarButton(buttonFlow: .main(.contacts))
|
||||
SharedTabBarButton(buttonFlow: .main(.contacts(.list)))
|
||||
SharedTabBarButton(buttonFlow: .main(.conversations))
|
||||
SharedTabBarButton(buttonFlow: .main(.settings))
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ private struct SharedTabBarButton: View {
|
|||
|
||||
var buttonTitle: String {
|
||||
switch buttonFlow {
|
||||
case .main(.contacts):
|
||||
case .main(.contacts(.list)):
|
||||
return "Contacts"
|
||||
|
||||
case .main(.conversations):
|
||||
|
|
|
@ -5,6 +5,9 @@ options:
|
|||
postGenCommand: swiftgen
|
||||
|
||||
packages:
|
||||
SwiftfulRouting:
|
||||
url: https://github.com/SwiftfulThinking/SwiftfulRouting
|
||||
majorVersion: 5.3.5
|
||||
MartinOMEMO:
|
||||
url: https://github.com/tigase/MartinOMEMO
|
||||
majorVersion: 2.2.3
|
||||
|
@ -74,6 +77,8 @@ targets:
|
|||
- sdk: Security.framework
|
||||
# - framework: Lib/WebRTC.xcframework
|
||||
# - target: Engine
|
||||
- package: SwiftfulRouting
|
||||
link: true
|
||||
- package: MartinOMEMO
|
||||
link: true
|
||||
- package: KeychainAccess
|
||||
|
|
Loading…
Reference in a new issue