This commit is contained in:
spaced4ndy
2024-05-06 15:40:27 +04:00
parent c7d045a4fa
commit bd664ddd33
4 changed files with 208 additions and 38 deletions
@@ -0,0 +1,149 @@
//
// ContactsView.swift
// SimpleX (iOS)
//
// Created by spaced4ndy on 06.05.2024.
// Copyright © 2024 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct ContactsView: View {
@EnvironmentObject var chatModel: ChatModel
@State private var searchMode = false
@FocusState private var searchFocussed
@State private var searchText = ""
@AppStorage(DEFAULT_ONE_HAND_UI) private var oneHandUI = true
var body: some View {
if #available(iOS 16.0, *) {
viewBody.scrollDismissesKeyboard(.immediately)
} else {
viewBody
}
}
private var viewBody: some View {
VStack {
contactList
}
.listStyle(.plain)
}
@ViewBuilder private var contactList: some View {
let cs = filteredContacts()
ZStack {
VStack {
List {
if !chatModel.chats.isEmpty {
ContactsSearchBar(
searchMode: $searchMode,
searchFocussed: $searchFocussed,
searchText: $searchText
)
.listRowSeparator(.hidden)
.frame(maxWidth: .infinity)
}
ForEach(cs, id: \.viewId) { chat in
ChatListNavLink(chat: chat)
.padding(.trailing, -16)
.disabled(chatModel.chatRunning != true || chatModel.deletedChats.contains(chat.chatInfo.id))
}
.offset(x: -8)
}
}
if cs.isEmpty && !chatModel.chats.isEmpty {
Text("No filtered contacts")
.foregroundColor(.secondary)
}
}
}
private func filteredContacts() -> [Chat] {
let s = searchString()
return chatModel.chats.filter { chat in
let cInfo = chat.chatInfo
switch cInfo {
case let .direct(contact):
return s == ""
? true
: (viewNameContains(cInfo, s) ||
contact.profile.displayName.localizedLowercase.contains(s) ||
contact.fullName.localizedLowercase.contains(s))
default:
return false
}
}
func searchString() -> String {
searchText.trimmingCharacters(in: .whitespaces).localizedLowercase
}
func viewNameContains(_ cInfo: ChatInfo, _ s: String) -> Bool {
cInfo.chatViewName.localizedLowercase.contains(s)
}
}
}
struct ContactsSearchBar: View {
@EnvironmentObject var m: ChatModel
@Binding var searchMode: Bool
@FocusState.Binding var searchFocussed: Bool
@Binding var searchText: String
var body: some View {
VStack(spacing: 12) {
HStack(spacing: 12) {
HStack(spacing: 4) {
Image(systemName: "magnifyingglass")
TextField("Search", text: $searchText)
.focused($searchFocussed)
.frame(maxWidth: .infinity)
if !searchText.isEmpty {
Image(systemName: "xmark.circle.fill")
.onTapGesture {
searchText = ""
}
}
}
.padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7))
.foregroundColor(.secondary)
.background(Color(.tertiarySystemFill))
.cornerRadius(10.0)
if searchFocussed {
Text("Cancel")
.foregroundColor(.accentColor)
.onTapGesture {
searchText = ""
searchFocussed = false
}
}
}
}
.onChange(of: searchFocussed) { sf in
withAnimation { searchMode = sf }
}
}
}
struct ContactsView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.chats = [
Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: []
)
]
return Group {
ContactsView()
.environmentObject(chatModel)
ContactsView()
.environmentObject(ChatModel())
}
}
}
@@ -254,18 +254,6 @@ struct ChatsSearchBar: View {
}
}
// TODO remove
func chatsStoppedIcon() -> 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: {
Image(systemName: "exclamationmark.octagon.fill").foregroundColor(.red)
}
}
struct ChatsView_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
+47 -26
View File
@@ -182,32 +182,56 @@ struct HomeView: View {
.foregroundColor(homeTab == .chats ? .accentColor : .secondary)
}
private func newChatButton() -> some View {
Menu {
Button {
newChatMenuOption = .newGroup
@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: {
Text("Create group")
iconLabel("square.and.pencil", "New chat")
}
Button {
newChatMenuOption = .scanPaste
} label: {
Text("Scan / Paste link")
.foregroundColor(.secondary)
.sheet(item: $newChatMenuOption) { opt in
switch opt {
case .newContact: NewChatView(selection: .invite)
case .scanPaste: NewChatView(selection: .connect, showQRCodeScanner: true)
case .newGroup: AddGroupView()
}
}
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)
}
}
}
@@ -224,10 +248,7 @@ struct HomeView: View {
}
private func contactsView() -> some View {
// TODO
VStack {
Text("Contacts")
}
ContactsView()
}
@ViewBuilder private func chatsView() -> some View {
@@ -174,6 +174,7 @@
646BB38E283FDB6D001CE359 /* LocalAuthenticationUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */; };
647F090E288EA27B00644C40 /* GroupMemberInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */; };
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
6485F7C62BE8DB6500FAE413 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6485F7C52BE8DB6500FAE413 /* ContactsView.swift */; };
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
@@ -471,6 +472,7 @@
646BB38D283FDB6D001CE359 /* LocalAuthenticationUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalAuthenticationUtils.swift; sourceTree = "<group>"; };
647F090D288EA27B00644C40 /* GroupMemberInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupMemberInfoView.swift; sourceTree = "<group>"; };
648010AA281ADD15009009B9 /* CIFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIFileView.swift; sourceTree = "<group>"; };
6485F7C52BE8DB6500FAE413 /* ContactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsView.swift; sourceTree = "<group>"; };
648679AA2BC96A74006456E7 /* ChatItemForwardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemForwardingView.swift; sourceTree = "<group>"; };
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
@@ -586,6 +588,7 @@
5C5F4AC227A5E9AF00B51EF1 /* Chat */ = {
isa = PBXGroup;
children = (
6485F7C42BE8DB4F00FAE413 /* Contacts */,
6440CA01288AEC770062C672 /* Group */,
5CE4407427ADB657007B033A /* ChatItem */,
5CEACCE527DE977C000BD591 /* ComposeMessage */,
@@ -927,6 +930,14 @@
path = Group;
sourceTree = "<group>";
};
6485F7C42BE8DB4F00FAE413 /* Contacts */ = {
isa = PBXGroup;
children = (
6485F7C52BE8DB6500FAE413 /* ContactsView.swift */,
);
path = Contacts;
sourceTree = "<group>";
};
8C7D94982B8894D300B7B9E1 /* Migration */ = {
isa = PBXGroup;
children = (
@@ -1182,6 +1193,7 @@
5CB2084F28DA4B4800D024EC /* RTCServers.swift in Sources */,
5CB634AF29E4BB7D0066AD6B /* SetAppPasscodeView.swift in Sources */,
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */,
6485F7C62BE8DB6500FAE413 /* ContactsView.swift in Sources */,
5CBE6C12294487F7002D9531 /* VerifyCodeView.swift in Sources */,
3CDBCF4227FAE51000354CDD /* ComposeLinkView.swift in Sources */,
648679AB2BC96A74006456E7 /* ChatItemForwardingView.swift in Sources */,