wip
This commit is contained in:
parent
d0c45cd41d
commit
2e053afea9
|
@ -1,30 +0,0 @@
|
|||
import Combine
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
final class NavigationStore: ObservableObject {
|
||||
enum Flow: Equatable {
|
||||
enum Entering: Equatable {
|
||||
case welcome
|
||||
case login
|
||||
case registration
|
||||
}
|
||||
|
||||
enum Main: Equatable {
|
||||
enum Contacts: Equatable {
|
||||
case list
|
||||
case add
|
||||
}
|
||||
|
||||
case contacts(Contacts)
|
||||
case conversations
|
||||
case settings
|
||||
}
|
||||
|
||||
case start
|
||||
case entering(Entering)
|
||||
case main(Main)
|
||||
}
|
||||
|
||||
@Published var flow: Flow = .start
|
||||
}
|
|
@ -5,7 +5,6 @@ import SwiftUI
|
|||
@MainActor
|
||||
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
|
||||
|
@ -15,7 +14,7 @@ struct ConversationsClassic: App {
|
|||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
AppRootView()
|
||||
RootView()
|
||||
.environmentObject(clientsStore)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
"Login.btn" = "Continue";
|
||||
"Login.error" = "Check internet connection, and make sure that JID and password are correct";
|
||||
|
||||
// MARK: Tabs
|
||||
"Tabs.Name.contacts" = "Contacts";
|
||||
"Tabs.Name.conversations" = "Chats";
|
||||
"Tabs.Name.settings" = "Settings";
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import SwiftUI
|
||||
|
||||
struct AppRootView: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
switch navigation.flow {
|
||||
case .start:
|
||||
StartScreen()
|
||||
|
||||
case .entering(let kind):
|
||||
switch kind {
|
||||
case .welcome:
|
||||
WelcomeScreen()
|
||||
|
||||
case .login:
|
||||
LoginScreen()
|
||||
|
||||
case .registration:
|
||||
RegistrationScreen()
|
||||
}
|
||||
|
||||
case .main(let main):
|
||||
switch main {
|
||||
case .contacts(let kind):
|
||||
switch kind {
|
||||
case .list:
|
||||
ContactsScreen()
|
||||
|
||||
case .add:
|
||||
ContactsScreen()
|
||||
.fullScreenCover(isPresented: .constant(true)) {
|
||||
AddContactOrChannelScreen()
|
||||
}
|
||||
}
|
||||
|
||||
case .conversations:
|
||||
EmptyView()
|
||||
|
||||
case .settings:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ import Martin
|
|||
import SwiftUI
|
||||
|
||||
struct LoginScreen: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
@Environment(\.router) var router
|
||||
@EnvironmentObject var clientsStore: ClientsStore
|
||||
|
||||
enum Field {
|
||||
|
@ -88,9 +88,7 @@ struct LoginScreen: View {
|
|||
.disabled(!loginInputValid)
|
||||
|
||||
Button {
|
||||
withAnimation {
|
||||
navigation.flow = .entering(.welcome)
|
||||
}
|
||||
router.dismissScreen()
|
||||
} label: {
|
||||
Text("\(Image(systemName: "chevron.left")) \(L10n.Global.back)")
|
||||
.foregroundColor(.Material.Elements.active)
|
||||
|
@ -129,9 +127,6 @@ struct LoginScreen: View {
|
|||
clientsStore.addNewClient(client)
|
||||
isLoading = false
|
||||
isError = false
|
||||
if navigation.flow == .entering(.login) {
|
||||
navigation.flow = .main(.contacts(.list))
|
||||
}
|
||||
|
||||
case .failure:
|
||||
isLoading = false
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import SwiftUI
|
||||
|
||||
struct RegistrationScreen: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
@Environment(\.router) var router
|
||||
|
||||
public var body: some View {
|
||||
ZStack {
|
||||
Color.Material.Background.light
|
||||
Button {
|
||||
withAnimation {
|
||||
navigation.flow = .entering(.welcome)
|
||||
}
|
||||
router.dismissScreen()
|
||||
} label: {
|
||||
VStack {
|
||||
Text("Not yet implemented")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import SwiftUI
|
||||
|
||||
struct WelcomeScreen: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
@Environment(\.router) var router
|
||||
|
||||
public var body: some View {
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// background
|
||||
Color.Material.Background.light
|
||||
|
@ -33,16 +33,18 @@ struct WelcomeScreen: View {
|
|||
// buttons
|
||||
VStack(spacing: 16) {
|
||||
Button {
|
||||
withAnimation {
|
||||
navigation.flow = .entering(.login)
|
||||
router.showScreen(.push) { _ in
|
||||
LoginScreen()
|
||||
.navigationBarBackButtonHidden(true)
|
||||
}
|
||||
} label: {
|
||||
Text(L10n.Start.Btn.login)
|
||||
}
|
||||
.buttonStyle(SecondaryButtonStyle())
|
||||
Button {
|
||||
withAnimation {
|
||||
navigation.flow = .entering(.registration)
|
||||
router.showScreen(.push) { _ in
|
||||
RegistrationScreen()
|
||||
.navigationBarBackButtonHidden(true)
|
||||
}
|
||||
} label: {
|
||||
Text(L10n.Start.Btn.register)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import SwiftUI
|
||||
|
||||
struct AddContactOrChannelScreen: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
// @EnvironmentObject var store: AppStore
|
||||
|
||||
// enum Field {
|
||||
|
@ -32,9 +31,9 @@ struct AddContactOrChannelScreen: View {
|
|||
leftButton: .init(
|
||||
image: Image(systemName: "xmark"),
|
||||
action: {
|
||||
withAnimation {
|
||||
navigation.flow = .main(.contacts(.list))
|
||||
}
|
||||
// withAnimation {
|
||||
// navigation.flow = .main(.contacts(.list))
|
||||
// }
|
||||
// isPresented = false
|
||||
}
|
||||
),
|
|
@ -1,7 +1,6 @@
|
|||
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
|
||||
|
@ -23,9 +22,9 @@ struct ContactsScreen: View {
|
|||
rightButton: .init(
|
||||
image: Image(systemName: "plus"),
|
||||
action: {
|
||||
withAnimation {
|
||||
navigation.flow = .main(.contacts(.add))
|
||||
}
|
||||
// withAnimation {
|
||||
// navigation.flow = .main(.contacts(.add))
|
||||
// }
|
||||
// addPanelPresented = true
|
||||
}
|
||||
)
|
||||
|
@ -48,9 +47,6 @@ struct ContactsScreen: View {
|
|||
} else {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
// Tab bar
|
||||
SharedTabBar()
|
||||
}
|
||||
}
|
||||
// .task {
|
113
ConversationsClassic/View/Main/MainTabScreen.swift
Normal file
113
ConversationsClassic/View/Main/MainTabScreen.swift
Normal file
|
@ -0,0 +1,113 @@
|
|||
import Foundation
|
||||
import SwiftfulRouting
|
||||
import SwiftUI
|
||||
|
||||
private enum Tab {
|
||||
case conversations
|
||||
case contacts
|
||||
case settings
|
||||
}
|
||||
|
||||
struct MainTabScreen: View {
|
||||
@State private var selectedTab: Tab = .conversations
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Background color
|
||||
Color.Material.Background.light
|
||||
.ignoresSafeArea()
|
||||
|
||||
// Content
|
||||
VStack(spacing: 0) {
|
||||
switch selectedTab {
|
||||
case .conversations:
|
||||
Color.red
|
||||
// ConversationsScreen()
|
||||
|
||||
case .contacts:
|
||||
RouterView { _ in
|
||||
ContactsScreen()
|
||||
}
|
||||
|
||||
case .settings:
|
||||
Color.green
|
||||
// SettingsScreen()
|
||||
}
|
||||
|
||||
// Tab bar
|
||||
TabBar(selectedTab: $selectedTab)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct TabBar: View {
|
||||
@Binding var selectedTab: Tab
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Rectangle()
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 0.2)
|
||||
.foregroundColor(.Material.Shape.separator)
|
||||
HStack(spacing: 0) {
|
||||
TabBarButton(buttonType: .contacts, selectedTab: $selectedTab)
|
||||
TabBarButton(buttonType: .conversations, selectedTab: $selectedTab)
|
||||
TabBarButton(buttonType: .settings, selectedTab: $selectedTab)
|
||||
}
|
||||
.background(Color.Material.Background.dark)
|
||||
}
|
||||
.frame(height: 50)
|
||||
}
|
||||
}
|
||||
|
||||
private struct TabBarButton: View {
|
||||
let buttonType: Tab
|
||||
|
||||
@Binding var selectedTab: Tab
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
VStack(spacing: 2) {
|
||||
buttonImg
|
||||
.foregroundColor(buttonType == selectedTab ? .Material.Elements.active : .Material.Elements.inactive)
|
||||
.font(.system(size: 24, weight: .light))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text(buttonTitle)
|
||||
.font(.sub1)
|
||||
.foregroundColor(buttonType == selectedTab ? .Material.Text.main : .Material.Elements.inactive)
|
||||
}
|
||||
Rectangle()
|
||||
.foregroundColor(.white.opacity(0.01))
|
||||
.onTapGesture {
|
||||
selectedTab = buttonType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buttonImg: Image {
|
||||
switch buttonType {
|
||||
case .contacts:
|
||||
return Image(systemName: "person.2.fill")
|
||||
|
||||
case .conversations:
|
||||
return Image(systemName: "bubble.left.fill")
|
||||
|
||||
case .settings:
|
||||
return Image(systemName: "gearshape.fill")
|
||||
}
|
||||
}
|
||||
|
||||
var buttonTitle: String {
|
||||
switch buttonType {
|
||||
case .contacts:
|
||||
return L10n.Tabs.Name.contacts
|
||||
|
||||
case .conversations:
|
||||
return L10n.Tabs.Name.conversations
|
||||
|
||||
case .settings:
|
||||
return L10n.Tabs.Name.settings
|
||||
}
|
||||
}
|
||||
}
|
27
ConversationsClassic/View/RootView.swift
Normal file
27
ConversationsClassic/View/RootView.swift
Normal file
|
@ -0,0 +1,27 @@
|
|||
import SwiftfulRouting
|
||||
import SwiftUI
|
||||
|
||||
struct RootView: View {
|
||||
@EnvironmentObject var clientsStore: ClientsStore
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if clientsStore.ready {
|
||||
if clientsStore.clients.isEmpty {
|
||||
RouterView { _ in
|
||||
WelcomeScreen()
|
||||
}
|
||||
} else {
|
||||
RouterView { _ in
|
||||
MainTabScreen()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StartScreen()
|
||||
}
|
||||
}
|
||||
.task {
|
||||
clientsStore.startFetching()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,72 +7,72 @@ struct SharedTabBar: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 0.2)
|
||||
.foregroundColor(.Material.Shape.separator)
|
||||
HStack(spacing: 0) {
|
||||
SharedTabBarButton(buttonFlow: .main(.contacts(.list)))
|
||||
SharedTabBarButton(buttonFlow: .main(.conversations))
|
||||
SharedTabBarButton(buttonFlow: .main(.settings))
|
||||
}
|
||||
.background(Color.Material.Background.dark)
|
||||
// HStack(spacing: 0) {
|
||||
// SharedTabBarButton(buttonFlow: .main(.contacts(.list)))
|
||||
// SharedTabBarButton(buttonFlow: .main(.conversations))
|
||||
// SharedTabBarButton(buttonFlow: .main(.settings))
|
||||
// }
|
||||
// .background(Color.Material.Background.dark)
|
||||
}
|
||||
.frame(height: 50)
|
||||
}
|
||||
}
|
||||
|
||||
private struct SharedTabBarButton: View {
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
|
||||
let buttonFlow: NavigationStore.Flow
|
||||
// let buttonFlow: NavigationStore.Flow
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
VStack(spacing: 2) {
|
||||
buttonImg
|
||||
.foregroundColor(buttonFlow == navigation.flow ? .Material.Elements.active : .Material.Elements.inactive)
|
||||
// .foregroundColor(buttonFlow == navigation.flow ? .Material.Elements.active : .Material.Elements.inactive)
|
||||
.font(.system(size: 24, weight: .light))
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text(buttonTitle)
|
||||
.font(.sub1)
|
||||
.foregroundColor(buttonFlow == navigation.flow ? .Material.Text.main : .Material.Elements.inactive)
|
||||
// .foregroundColor(buttonFlow == navigation.flow ? .Material.Text.main : .Material.Elements.inactive)
|
||||
}
|
||||
Rectangle()
|
||||
.foregroundColor(.white.opacity(0.01))
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
navigation.flow = buttonFlow
|
||||
}
|
||||
// withAnimation {
|
||||
// navigation.flow = buttonFlow
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var buttonImg: Image {
|
||||
switch buttonFlow {
|
||||
case .main(.contacts):
|
||||
return Image(systemName: "person.2.fill")
|
||||
// switch buttonFlow {
|
||||
// case .main(.contacts):
|
||||
// return Image(systemName: "person.2.fill")
|
||||
//
|
||||
// case .main(.conversations):
|
||||
// return Image(systemName: "bubble.left.fill")
|
||||
//
|
||||
// case .main(.settings):
|
||||
// return Image(systemName: "gearshape.fill")
|
||||
|
||||
case .main(.conversations):
|
||||
return Image(systemName: "bubble.left.fill")
|
||||
|
||||
case .main(.settings):
|
||||
return Image(systemName: "gearshape.fill")
|
||||
|
||||
default:
|
||||
return Image(systemName: "questionmark.circle")
|
||||
}
|
||||
// default:
|
||||
// return Image(systemName: "questionmark.circle")
|
||||
// }
|
||||
Image(systemName: "questionmark.circle")
|
||||
}
|
||||
|
||||
var buttonTitle: String {
|
||||
switch buttonFlow {
|
||||
case .main(.contacts(.list)):
|
||||
return "Contacts"
|
||||
|
||||
case .main(.conversations):
|
||||
return "Chats"
|
||||
|
||||
case .main(.settings):
|
||||
return "Settings"
|
||||
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
""
|
||||
// switch buttonFlow {
|
||||
// case .main(.contacts(.list)):
|
||||
// return "Contacts"
|
||||
//
|
||||
// case .main(.conversations):
|
||||
// return "Chats"
|
||||
//
|
||||
// case .main(.settings):
|
||||
// return "Settings"
|
||||
//
|
||||
// default:
|
||||
// return "Unknown"
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import SwiftUI
|
|||
|
||||
struct StartScreen: View {
|
||||
@EnvironmentObject var clientsStore: ClientsStore
|
||||
@EnvironmentObject var navigation: NavigationStore
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
|
@ -13,16 +12,5 @@ struct StartScreen: View {
|
|||
.frame(width: 200, height: 200)
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.onAppear {
|
||||
clientsStore.startFetching()
|
||||
}
|
||||
.onChange(of: clientsStore.ready) { ready in
|
||||
if ready {
|
||||
let flow: NavigationStore.Flow = clientsStore.clients.isEmpty ? .entering(.welcome) : .main(.conversations)
|
||||
withAnimation {
|
||||
navigation.flow = flow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue