Files
simplex-chat/apps/ios/Shared/Views/Home/HomeView.swift
T
spaced4ndy c921339bc2 sizes
2024-05-06 18:10:29 +04:00

294 lines
9.3 KiB
Swift

//
// HomeView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 01.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
enum HomeTab {
case contacts
case chats
}
struct HomeView: View {
@EnvironmentObject var chatModel: ChatModel
@Binding var showSettings: Bool
@State private var homeTab: HomeTab = .chats
@State private var userPickerVisible = false
@State private var showConnectDesktop = false
@State private var newChatMenuOption: NewChatMenuOption? = nil
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = true
// init(homeTab: Binding<HomeTab>) {
// // Make the background color of the bottom toolbar fully transparent
// let appearance = UIToolbarAppearance()
// appearance.configureWithOpaqueBackground()
// appearance.shadowColor = .clear
// appearance.backgroundColor = .clear
// appearance.backgroundImage = UIImage()
// UIToolbar.appearance().standardAppearance = appearance
// UIToolbar.appearance().compactAppearance = appearance
// UIToolbar.appearance().scrollEdgeAppearance = appearance
//
// self._homeTab = homeTab
// }
var body: some View {
ZStack(alignment: .bottomLeading) {
NavStackCompat(
isActive: Binding(
get: { chatModel.chatId != nil },
set: { _ in }
),
destination: chatView
) {
// ZStack {
VStack {
switch homeTab {
case .contacts: contactsView()
case .chats: chatsView()
}
}
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
settingsButton()
Spacer()
contactsButton()
Spacer()
chatsButton()
Spacer()
newChatButton()
}
}
// VStack {
// Spacer()
// bottomToolbar()
// .background(BlurView(style: .systemThinMaterial).ignoresSafeArea())
// }
// }
// if homeTab == .chats {
// VStack {
// Spacer()
// ChatsSearchBar(
// searchMode: $searchMode,
// searchFocussed: $searchFocussed,
// searchText: $searchText,
// searchShowingSimplexLink: $searchShowingSimplexLink,
// searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink
// )
// .padding(.horizontal)
// .padding(.top, 8)
// .background(BlurView(style: .systemMaterial))
// }
// }
}
if userPickerVisible {
Rectangle().fill(.white.opacity(0.001)).onTapGesture {
withAnimation {
userPickerVisible.toggle()
}
}
}
UserPicker(
showSettings: $showSettings,
showConnectDesktop: $showConnectDesktop,
userPickerVisible: $userPickerVisible
)
}
.sheet(isPresented: $showConnectDesktop) {
ConnectDesktopView()
}
}
// private func bottomToolbar() -> some View {
// HStack {
// settingsButton()
// Spacer()
// contactsButton()
// Spacer()
// chatsButton()
// Spacer()
// newChatButton()
// }
// .padding(.horizontal, 12)
// .padding(.horizontal)
// .frame(maxWidth: .infinity)
// }
@ViewBuilder private func settingsButton() -> some View {
let user = chatModel.currentUser ?? User.sampleData
let multiUser = chatModel.users.filter({ u in u.user.activeUser || !u.user.hidden }).count > 1
Button {
if multiUser {
withAnimation {
userPickerVisible.toggle()
}
} else {
showSettings = true
}
} label: {
if user.image != nil {
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: user.image, size: 32, color: Color(uiColor: .quaternaryLabel))
.padding(.trailing, 4)
let allRead = chatModel.users
.filter { u in !u.user.activeUser && !u.user.hidden }
.allSatisfy { u in u.unreadCount == 0 }
if !allRead {
userUnreadBadge(size: 12)
}
}
} else {
iconLabel(
multiUser ? "person.2.fill" : "gearshape.fill",
multiUser ? "Users" : "Settings"
)
}
}
.foregroundColor(.secondary)
}
private func userUnreadBadge(_ text: Text? = Text(" "), size: CGFloat = 18) -> some View {
Circle()
.frame(width: size, height: size)
.foregroundColor(.accentColor)
}
private func contactsButton() -> some View {
Button {
homeTab = .contacts
} label: {
iconLabel("person.crop.circle.fill", "Contacts")
}
.foregroundColor(homeTab == .contacts ? .accentColor : .secondary)
}
private func chatsButton() -> some View {
Button {
homeTab = .chats
} label: {
iconLabel("message.fill", "Chats")
}
.foregroundColor(homeTab == .chats ? .accentColor : .secondary)
}
@ViewBuilder private func newChatButton() -> some View {
if case .some(false) = chatModel.chatRunning {
chatsStoppedButton()
} else {
Menu {
Button {
newChatMenuOption = .newGroup
} label: {
Text("Create group")
}
Button {
newChatMenuOption = .scanPaste
} label: {
Text("Scan / Paste link")
}
Button {
newChatMenuOption = .newContact
} label: {
Text("Add contact")
}
} label: {
iconLabel("square.and.pencil", "New chat")
}
.foregroundColor(.secondary)
.sheet(item: $newChatMenuOption) { opt in
switch opt {
case .newContact: NewChatView(selection: .invite)
case .scanPaste: NewChatView(selection: .connect, showQRCodeScanner: true)
case .newGroup: AddGroupView()
}
}
}
}
func chatsStoppedButton() -> some View {
Button {
AlertManager.shared.showAlertMsg(
title: "Chat is stopped",
message: "You can start chat via app Settings / Database or by restarting the app"
)
} label: {
VStack(spacing: 4) {
Image(systemName: "exclamationmark.octagon.fill")
.resizable()
.scaledToFit()
.foregroundColor(.red)
.frame(width: 24, height: 24)
Text("Stopped")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
private func iconLabel(_ image: String, _ title: LocalizedStringKey) -> some View {
VStack(spacing: 4) {
Image(systemName: image)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
Text(title)
.font(.caption)
}
}
@ViewBuilder private func contactsView() -> some View {
if oneHandUI {
ContactsView()
.padding(.vertical, 5)
} else {
ContactsView()
.padding(.top, 5)
}
}
@ViewBuilder private func chatsView() -> some View {
// TODO reverse scale effect for swipe actions
if oneHandUI {
ChatsView()
.padding(.vertical, 5)
} else {
ChatsView()
.padding(.top, 5)
}
}
@ViewBuilder private func chatView() -> some View {
if let chatId = chatModel.chatId, let chat = chatModel.getChat(chatId) {
ChatView(chat: chat).onAppear {
loadChat(chat: chat)
}
}
}
}
struct BlurView: UIViewRepresentable {
let style: UIBlurEffect.Style
func makeUIView(context: Context) -> UIVisualEffectView {
let view = UIVisualEffectView(effect: UIBlurEffect(style: style))
return view
}
func updateUIView(_ uiView: UIVisualEffectView, context: Context) {}
}
#Preview {
HomeView(showSettings: Binding.constant(false))
}