ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
//
|
|
|
|
// NewChatMenuButton.swift
|
|
|
|
// SimpleX (iOS)
|
|
|
|
//
|
|
|
|
// Created by spaced4ndy on 28.11.2023.
|
|
|
|
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import SwiftUI
|
2024-08-05 12:58:24 +01:00
|
|
|
import SimpleXChat
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
|
2024-08-05 12:58:24 +01:00
|
|
|
enum ContactType: Int {
|
|
|
|
case card, request, recent, chatDeleted, unlisted
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct NewChatMenuButton: View {
|
2024-10-11 01:08:03 +07:00
|
|
|
// do not use chatModel here because it prevents showing AddGroupMembersView after group creation and QR code after link creation on iOS 16
|
|
|
|
// @EnvironmentObject var chatModel: ChatModel
|
2024-08-05 12:58:24 +01:00
|
|
|
@State private var showNewChatSheet = false
|
|
|
|
@State private var alert: SomeAlert? = nil
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
|
|
|
|
var body: some View {
|
2024-07-03 16:59:46 +04:00
|
|
|
Button {
|
2024-08-05 12:58:24 +01:00
|
|
|
showNewChatSheet = true
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
} label: {
|
|
|
|
Image(systemName: "square.and.pencil")
|
|
|
|
.resizable()
|
|
|
|
.scaledToFit()
|
|
|
|
.frame(width: 24, height: 24)
|
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
.appSheet(isPresented: $showNewChatSheet) {
|
2024-11-26 14:43:39 +04:00
|
|
|
NewChatSheet()
|
2024-08-05 12:58:24 +01:00
|
|
|
.environment(\EnvironmentValues.refresh as! WritableKeyPath<EnvironmentValues, RefreshAction?>, nil)
|
|
|
|
}
|
2024-08-22 15:02:32 +01:00
|
|
|
.alert(item: $alert) { a in
|
2024-08-05 12:58:24 +01:00
|
|
|
return a.alert
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private var indent: CGFloat = 36
|
|
|
|
|
|
|
|
struct NewChatSheet: View {
|
|
|
|
@EnvironmentObject var theme: AppTheme
|
|
|
|
@State private var baseContactTypes: [ContactType] = [.card, .request, .recent]
|
|
|
|
@EnvironmentObject var chatModel: ChatModel
|
|
|
|
@State private var searchMode = false
|
|
|
|
@FocusState var searchFocussed: Bool
|
|
|
|
@State private var searchText = ""
|
|
|
|
@State private var searchShowingSimplexLink = false
|
|
|
|
@State private var searchChatFilteredBySimplexLink: String? = nil
|
2024-08-22 15:02:32 +01:00
|
|
|
@State private var alert: SomeAlert?
|
2024-08-10 22:18:49 +01:00
|
|
|
|
|
|
|
// Sheet height management
|
|
|
|
@State private var isAddContactActive = false
|
|
|
|
@State private var isScanPasteLinkActive = false
|
|
|
|
@State private var isLargeSheet = false
|
|
|
|
@State private var allowSmallSheet = true
|
|
|
|
|
|
|
|
@AppStorage(GROUP_DEFAULT_ONE_HAND_UI, store: groupDefaults) private var oneHandUI = true
|
|
|
|
|
2024-08-05 12:58:24 +01:00
|
|
|
var body: some View {
|
2024-08-10 22:18:49 +01:00
|
|
|
let showArchive = !filterContactTypes(chats: chatModel.chats, contactTypes: [.chatDeleted]).isEmpty
|
|
|
|
let v = NavigationView {
|
|
|
|
viewBody(showArchive)
|
2024-08-09 12:40:39 +01:00
|
|
|
.navigationTitle("New message")
|
2024-08-05 21:22:09 +04:00
|
|
|
.navigationBarTitleDisplayMode(.large)
|
2024-08-05 12:58:24 +01:00
|
|
|
.navigationBarHidden(searchMode)
|
|
|
|
.modifier(ThemedBackground(grouped: true))
|
2024-08-22 15:02:32 +01:00
|
|
|
.alert(item: $alert) { a in
|
|
|
|
return a.alert
|
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
2024-08-10 22:18:49 +01:00
|
|
|
if #available(iOS 16.0, *), oneHandUI {
|
|
|
|
let sheetHeight: CGFloat = showArchive ? 575 : 500
|
|
|
|
v.presentationDetents(
|
|
|
|
allowSmallSheet ? [.height(sheetHeight), .large] : [.large],
|
|
|
|
selection: Binding(
|
|
|
|
get: { isLargeSheet || !allowSmallSheet ? .large : .height(sheetHeight) },
|
|
|
|
set: { isLargeSheet = $0 == .large }
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
v
|
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
2024-08-10 22:18:49 +01:00
|
|
|
|
2025-05-11 14:15:14 +01:00
|
|
|
private func viewBody(_ showArchive: Bool) -> some View {
|
2024-08-05 12:58:24 +01:00
|
|
|
List {
|
|
|
|
HStack {
|
|
|
|
ContactsListSearchBar(
|
|
|
|
searchMode: $searchMode,
|
|
|
|
searchFocussed: $searchFocussed,
|
|
|
|
searchText: $searchText,
|
|
|
|
searchShowingSimplexLink: $searchShowingSimplexLink,
|
|
|
|
searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink
|
|
|
|
)
|
|
|
|
.frame(maxWidth: .infinity)
|
|
|
|
}
|
|
|
|
.listRowSeparator(.hidden)
|
|
|
|
.listRowBackground(Color.clear)
|
|
|
|
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
|
|
|
|
|
|
|
if (searchText.isEmpty) {
|
|
|
|
Section {
|
2024-08-10 22:18:49 +01:00
|
|
|
NavigationLink(isActive: $isAddContactActive) {
|
2024-11-26 14:43:39 +04:00
|
|
|
NewChatView(selection: .invite)
|
2024-08-05 12:58:24 +01:00
|
|
|
.navigationTitle("New chat")
|
|
|
|
.modifier(ThemedBackground(grouped: true))
|
|
|
|
.navigationBarTitleDisplayMode(.large)
|
|
|
|
} label: {
|
2024-11-26 14:43:39 +04:00
|
|
|
navigateOnTap(Label("Create 1-time link", systemImage: "link.badge.plus")) {
|
2024-08-10 22:18:49 +01:00
|
|
|
isAddContactActive = true
|
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
2024-08-10 22:18:49 +01:00
|
|
|
NavigationLink(isActive: $isScanPasteLinkActive) {
|
2024-11-26 14:43:39 +04:00
|
|
|
NewChatView(selection: .connect, showQRCodeScanner: true)
|
2024-08-05 12:58:24 +01:00
|
|
|
.navigationTitle("New chat")
|
|
|
|
.modifier(ThemedBackground(grouped: true))
|
|
|
|
.navigationBarTitleDisplayMode(.large)
|
|
|
|
} label: {
|
2024-08-10 22:18:49 +01:00
|
|
|
navigateOnTap(Label("Scan / Paste link", systemImage: "qrcode")) {
|
|
|
|
isScanPasteLinkActive = true
|
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
|
|
|
NavigationLink {
|
|
|
|
AddGroupView()
|
|
|
|
.navigationTitle("Create secret group")
|
|
|
|
.modifier(ThemedBackground(grouped: true))
|
|
|
|
.navigationBarTitleDisplayMode(.large)
|
|
|
|
} label: {
|
2024-08-08 01:39:05 +04:00
|
|
|
Label("Create group", systemImage: "person.2.circle.fill")
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-10 22:18:49 +01:00
|
|
|
if (showArchive) {
|
2024-08-05 12:58:24 +01:00
|
|
|
Section {
|
|
|
|
NavigationLink {
|
|
|
|
DeletedChats()
|
|
|
|
} label: {
|
2024-08-06 19:20:54 +01:00
|
|
|
newChatActionButton("archivebox", color: theme.colors.secondary) { Text("Archived contacts") }
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ContactsList(
|
|
|
|
baseContactTypes: $baseContactTypes,
|
|
|
|
searchMode: $searchMode,
|
|
|
|
searchText: $searchText,
|
|
|
|
header: "Your Contacts",
|
|
|
|
searchFocussed: $searchFocussed,
|
|
|
|
searchShowingSimplexLink: $searchShowingSimplexLink,
|
|
|
|
searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink,
|
|
|
|
showDeletedChatIcon: true
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-10 22:18:49 +01:00
|
|
|
/// Extends label's tap area to match `.insetGrouped` list row insets
|
|
|
|
private func navigateOnTap<L: View>(_ label: L, setActive: @escaping () -> Void) -> some View {
|
|
|
|
label
|
|
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
|
|
.padding(.leading, 16).padding(.vertical, 8).padding(.trailing, 32)
|
|
|
|
.contentShape(Rectangle())
|
|
|
|
.onTapGesture {
|
|
|
|
isLargeSheet = true
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
allowSmallSheet = false
|
|
|
|
setActive()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.padding(.leading, -16).padding(.vertical, -8).padding(.trailing, -32)
|
|
|
|
}
|
|
|
|
|
2024-08-05 12:58:24 +01:00
|
|
|
func newChatActionButton<Content : View>(_ icon: String, color: Color/* = .secondary*/, content: @escaping () -> Content) -> some View {
|
|
|
|
ZStack(alignment: .leading) {
|
2024-08-08 01:39:05 +04:00
|
|
|
Image(systemName: icon)
|
|
|
|
.resizable()
|
|
|
|
.scaledToFit()
|
|
|
|
.frame(maxWidth: 24, maxHeight: 24, alignment: .center)
|
2024-08-05 12:58:24 +01:00
|
|
|
.symbolRenderingMode(.monochrome)
|
|
|
|
.foregroundColor(color)
|
|
|
|
content().foregroundColor(theme.colors.onBackground).padding(.leading, indent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-19 10:48:26 +00:00
|
|
|
func chatContactType(_ chat: Chat) -> ContactType {
|
2024-08-05 12:58:24 +01:00
|
|
|
switch chat.chatInfo {
|
|
|
|
case .contactRequest:
|
|
|
|
return .request
|
|
|
|
case let .direct(contact):
|
2024-09-04 18:12:41 +01:00
|
|
|
if contact.activeConn == nil && contact.profile.contactLink != nil && contact.active {
|
2024-08-05 12:58:24 +01:00
|
|
|
return .card
|
|
|
|
} else if contact.chatDeleted {
|
|
|
|
return .chatDeleted
|
|
|
|
} else if contact.contactStatus == .active {
|
|
|
|
return .recent
|
|
|
|
} else {
|
|
|
|
return .unlisted
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return .unlisted
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func filterContactTypes(chats: [Chat], contactTypes: [ContactType]) -> [Chat] {
|
|
|
|
return chats.filter { chat in
|
2024-12-19 10:48:26 +00:00
|
|
|
contactTypes.contains(chatContactType(chat))
|
2024-08-05 12:58:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ContactsList: View {
|
|
|
|
@EnvironmentObject var theme: AppTheme
|
|
|
|
@EnvironmentObject var chatModel: ChatModel
|
|
|
|
@Binding var baseContactTypes: [ContactType]
|
|
|
|
@Binding var searchMode: Bool
|
|
|
|
@Binding var searchText: String
|
|
|
|
var header: String? = nil
|
|
|
|
@FocusState.Binding var searchFocussed: Bool
|
|
|
|
@Binding var searchShowingSimplexLink: Bool
|
|
|
|
@Binding var searchChatFilteredBySimplexLink: String?
|
|
|
|
var showDeletedChatIcon: Bool
|
|
|
|
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
|
|
|
|
|
|
|
|
var body: some View {
|
|
|
|
let contactTypes = contactTypesSearchTargets(baseContactTypes: baseContactTypes, searchEmpty: searchText.isEmpty)
|
|
|
|
let contactChats = filterContactTypes(chats: chatModel.chats, contactTypes: contactTypes)
|
|
|
|
let filteredContactChats = filteredContactChats(
|
|
|
|
showUnreadAndFavorites: showUnreadAndFavorites,
|
|
|
|
searchShowingSimplexLink: searchShowingSimplexLink,
|
|
|
|
searchChatFilteredBySimplexLink: searchChatFilteredBySimplexLink,
|
|
|
|
searchText: searchText,
|
|
|
|
contactChats: contactChats
|
|
|
|
)
|
|
|
|
|
|
|
|
if !filteredContactChats.isEmpty {
|
|
|
|
Section(header: Group {
|
|
|
|
if let header = header {
|
|
|
|
Text(header)
|
|
|
|
.textCase(.uppercase)
|
|
|
|
.foregroundColor(theme.colors.secondary)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
) {
|
|
|
|
ForEach(filteredContactChats, id: \.viewId) { chat in
|
|
|
|
ContactListNavLink(chat: chat, showDeletedChatIcon: showDeletedChatIcon)
|
|
|
|
.disabled(chatModel.chatRunning != true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if filteredContactChats.isEmpty && !contactChats.isEmpty {
|
|
|
|
noResultSection(text: "No filtered contacts")
|
|
|
|
} else if contactChats.isEmpty {
|
|
|
|
noResultSection(text: "No contacts")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-11 14:15:14 +01:00
|
|
|
private func noResultSection(text: String) -> some View {
|
2024-08-05 12:58:24 +01:00
|
|
|
Section {
|
|
|
|
Text(text)
|
|
|
|
.foregroundColor(theme.colors.secondary)
|
|
|
|
.frame(maxWidth: .infinity, alignment: .center)
|
|
|
|
|
|
|
|
}
|
|
|
|
.listRowSeparator(.hidden)
|
|
|
|
.listRowBackground(Color.clear)
|
|
|
|
.listRowInsets(EdgeInsets(top: 7, leading: 0, bottom: 7, trailing: 0))
|
|
|
|
}
|
|
|
|
|
|
|
|
private func contactTypesSearchTargets(baseContactTypes: [ContactType], searchEmpty: Bool) -> [ContactType] {
|
|
|
|
if baseContactTypes.contains(.chatDeleted) || searchEmpty {
|
|
|
|
return baseContactTypes
|
|
|
|
} else {
|
|
|
|
return baseContactTypes + [.chatDeleted]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func chatsByTypeComparator(chat1: Chat, chat2: Chat) -> Bool {
|
2024-12-19 10:48:26 +00:00
|
|
|
let chat1Type = chatContactType(chat1)
|
|
|
|
let chat2Type = chatContactType(chat2)
|
2024-08-05 12:58:24 +01:00
|
|
|
|
|
|
|
if chat1Type.rawValue < chat2Type.rawValue {
|
|
|
|
return true
|
|
|
|
} else if chat1Type.rawValue > chat2Type.rawValue {
|
|
|
|
return false
|
|
|
|
} else {
|
|
|
|
return chat2.chatInfo.chatTs < chat1.chatInfo.chatTs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func filterChat(chat: Chat, searchText: String, showUnreadAndFavorites: Bool) -> Bool {
|
|
|
|
var meetsPredicate = true
|
|
|
|
let s = searchText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
|
|
let cInfo = chat.chatInfo
|
|
|
|
|
|
|
|
if !searchText.isEmpty {
|
|
|
|
if (!cInfo.chatViewName.lowercased().contains(searchText.lowercased())) {
|
|
|
|
if case let .direct(contact) = cInfo {
|
|
|
|
meetsPredicate = contact.profile.displayName.lowercased().contains(s) || contact.fullName.lowercased().contains(s)
|
|
|
|
} else {
|
|
|
|
meetsPredicate = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if showUnreadAndFavorites {
|
|
|
|
meetsPredicate = meetsPredicate && (cInfo.chatSettings?.favorite ?? false)
|
|
|
|
}
|
|
|
|
|
|
|
|
return meetsPredicate
|
|
|
|
}
|
|
|
|
|
|
|
|
func filteredContactChats(
|
|
|
|
showUnreadAndFavorites: Bool,
|
|
|
|
searchShowingSimplexLink: Bool,
|
|
|
|
searchChatFilteredBySimplexLink: String?,
|
|
|
|
searchText: String,
|
|
|
|
contactChats: [Chat]
|
|
|
|
) -> [Chat] {
|
|
|
|
let linkChatId = searchChatFilteredBySimplexLink
|
|
|
|
let s = searchShowingSimplexLink ? "" : searchText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
|
|
|
|
|
|
let filteredChats: [Chat]
|
|
|
|
|
|
|
|
if let linkChatId = linkChatId {
|
|
|
|
filteredChats = contactChats.filter { $0.id == linkChatId }
|
|
|
|
} else {
|
|
|
|
filteredChats = contactChats.filter { chat in
|
|
|
|
filterChat(chat: chat, searchText: s, showUnreadAndFavorites: showUnreadAndFavorites)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return filteredChats.sorted(by: chatsByTypeComparator)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ContactsListSearchBar: View {
|
|
|
|
@EnvironmentObject var m: ChatModel
|
|
|
|
@EnvironmentObject var theme: AppTheme
|
|
|
|
@Binding var searchMode: Bool
|
|
|
|
@FocusState.Binding var searchFocussed: Bool
|
|
|
|
@Binding var searchText: String
|
|
|
|
@Binding var searchShowingSimplexLink: Bool
|
|
|
|
@Binding var searchChatFilteredBySimplexLink: String?
|
|
|
|
@State private var ignoreSearchTextChange = false
|
|
|
|
@State private var alert: PlanAndConnectAlert?
|
|
|
|
@State private var sheet: PlanAndConnectActionSheet?
|
|
|
|
@AppStorage(DEFAULT_SHOW_UNREAD_AND_FAVORITES) private var showUnreadAndFavorites = false
|
|
|
|
|
|
|
|
var body: some View {
|
|
|
|
HStack(spacing: 12) {
|
|
|
|
HStack(spacing: 4) {
|
|
|
|
Spacer()
|
|
|
|
.frame(width: 8)
|
|
|
|
Image(systemName: "magnifyingglass")
|
|
|
|
.resizable()
|
|
|
|
.scaledToFit()
|
|
|
|
.frame(width: 16, height: 16)
|
|
|
|
TextField("Search or paste SimpleX link", text: $searchText)
|
|
|
|
.foregroundColor(searchShowingSimplexLink ? theme.colors.secondary : theme.colors.onBackground)
|
|
|
|
.disabled(searchShowingSimplexLink)
|
|
|
|
.focused($searchFocussed)
|
|
|
|
.frame(maxWidth: .infinity)
|
|
|
|
if !searchText.isEmpty {
|
|
|
|
Image(systemName: "xmark.circle.fill")
|
|
|
|
.resizable()
|
|
|
|
.scaledToFit()
|
|
|
|
.frame(width: 16, height: 16)
|
|
|
|
.onTapGesture {
|
|
|
|
searchText = ""
|
|
|
|
}
|
|
|
|
}
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
.padding(EdgeInsets(top: 7, leading: 7, bottom: 7, trailing: 7))
|
|
|
|
.foregroundColor(theme.colors.secondary)
|
2024-08-08 01:39:05 +04:00
|
|
|
.background(Color(uiColor: .secondarySystemGroupedBackground))
|
2024-08-05 12:58:24 +01:00
|
|
|
.cornerRadius(10.0)
|
|
|
|
|
|
|
|
if searchFocussed {
|
|
|
|
Text("Cancel")
|
|
|
|
.foregroundColor(theme.colors.primary)
|
|
|
|
.onTapGesture {
|
|
|
|
searchText = ""
|
|
|
|
searchFocussed = false
|
|
|
|
}
|
|
|
|
} else if m.chats.count > 0 {
|
|
|
|
toggleFilterButton()
|
|
|
|
}
|
|
|
|
}
|
2024-08-08 01:39:05 +04:00
|
|
|
.padding(.top, 24)
|
2024-08-05 12:58:24 +01:00
|
|
|
.onChange(of: searchFocussed) { sf in
|
|
|
|
withAnimation { searchMode = sf }
|
|
|
|
}
|
|
|
|
.onChange(of: searchText) { t in
|
|
|
|
if ignoreSearchTextChange {
|
|
|
|
ignoreSearchTextChange = false
|
|
|
|
} else {
|
|
|
|
if let link = strHasSingleSimplexLink(t.trimmingCharacters(in: .whitespaces)) { // if SimpleX link is pasted, show connection dialogue
|
|
|
|
searchFocussed = false
|
|
|
|
if case let .simplexLink(linkType, _, smpHosts) = link.format {
|
|
|
|
ignoreSearchTextChange = true
|
|
|
|
searchText = simplexLinkText(linkType, smpHosts)
|
|
|
|
}
|
|
|
|
searchShowingSimplexLink = true
|
|
|
|
searchChatFilteredBySimplexLink = nil
|
|
|
|
connect(link.text)
|
|
|
|
} else {
|
|
|
|
if t != "" { // if some other text is pasted, enter search mode
|
|
|
|
searchFocussed = true
|
|
|
|
}
|
|
|
|
searchShowingSimplexLink = false
|
|
|
|
searchChatFilteredBySimplexLink = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.alert(item: $alert) { a in
|
|
|
|
planAndConnectAlert(a, dismiss: true, cleanup: { searchText = "" })
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
}
|
2024-08-05 12:58:24 +01:00
|
|
|
.actionSheet(item: $sheet) { s in
|
|
|
|
planAndConnectActionSheet(s, dismiss: true, cleanup: { searchText = "" })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func toggleFilterButton() -> some View {
|
|
|
|
ZStack {
|
|
|
|
Color.clear
|
|
|
|
.frame(width: 22, height: 22)
|
|
|
|
Image(systemName: showUnreadAndFavorites ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease")
|
|
|
|
.resizable()
|
|
|
|
.scaledToFit()
|
|
|
|
.foregroundColor(showUnreadAndFavorites ? theme.colors.primary : theme.colors.secondary)
|
|
|
|
.frame(width: showUnreadAndFavorites ? 22 : 16, height: showUnreadAndFavorites ? 22 : 16)
|
|
|
|
.onTapGesture {
|
|
|
|
showUnreadAndFavorites = !showUnreadAndFavorites
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func connect(_ link: String) {
|
|
|
|
planAndConnect(
|
|
|
|
link,
|
|
|
|
showAlert: { alert = $0 },
|
|
|
|
showActionSheet: { sheet = $0 },
|
|
|
|
dismiss: true,
|
|
|
|
incognito: nil,
|
|
|
|
filterKnownContact: { searchChatFilteredBySimplexLink = $0.id }
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct DeletedChats: View {
|
|
|
|
@State private var baseContactTypes: [ContactType] = [.chatDeleted]
|
|
|
|
@State private var searchMode = false
|
|
|
|
@FocusState var searchFocussed: Bool
|
|
|
|
@State private var searchText = ""
|
|
|
|
@State private var searchShowingSimplexLink = false
|
|
|
|
@State private var searchChatFilteredBySimplexLink: String? = nil
|
|
|
|
|
|
|
|
var body: some View {
|
|
|
|
List {
|
|
|
|
ContactsListSearchBar(
|
|
|
|
searchMode: $searchMode,
|
|
|
|
searchFocussed: $searchFocussed,
|
|
|
|
searchText: $searchText,
|
|
|
|
searchShowingSimplexLink: $searchShowingSimplexLink,
|
|
|
|
searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink
|
|
|
|
)
|
|
|
|
.listRowSeparator(.hidden)
|
|
|
|
.listRowBackground(Color.clear)
|
|
|
|
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
|
|
|
.frame(maxWidth: .infinity)
|
|
|
|
|
|
|
|
ContactsList(
|
|
|
|
baseContactTypes: $baseContactTypes,
|
|
|
|
searchMode: $searchMode,
|
|
|
|
searchText: $searchText,
|
|
|
|
searchFocussed: $searchFocussed,
|
|
|
|
searchShowingSimplexLink: $searchShowingSimplexLink,
|
|
|
|
searchChatFilteredBySimplexLink: $searchChatFilteredBySimplexLink,
|
|
|
|
showDeletedChatIcon: false
|
|
|
|
)
|
|
|
|
}
|
2024-08-08 01:39:05 +04:00
|
|
|
.navigationTitle("Archived contacts")
|
|
|
|
.navigationBarTitleDisplayMode(.large)
|
2024-08-05 12:58:24 +01:00
|
|
|
.navigationBarHidden(searchMode)
|
|
|
|
.modifier(ThemedBackground(grouped: true))
|
|
|
|
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#Preview {
|
2024-08-05 12:58:24 +01:00
|
|
|
NewChatMenuButton()
|
ios: rework UX of creating new connection (#3482)
* ios: connection UI (wip)
* custom search
* rework invite
* connect paste link ui
* scan rework, process errors, other fixes
* scan layout
* clear link on cancel
* improved search
* further improve search
* animation
* connect on paste in search
* layout
* layout
* layout
* layout, add conn
* delete unused invitation, create used invitation chat
* remove old views
* regular paste button
* new chat menu
* previews
* increase spacing
* animation, fix alerts
* swipe
* change text
* less sensitive gesture
* layout
* search cancel button transition
* slow down chat list animation (uses deprecated modifiers)
* icons
* update code scanner, layout
* manage camera permissions
* ask to delete unused invitation
* comment
* remove onDismiss
* don't filter chats on link in search, allow to paste text with link
* cleanup link after connection
* filter chat by link
* revert change
* show link descr
* disabled search
* underline
* filter own group
* simplify
* no animation
* add delay, move createInvitation
* update library
* possible fix for ios 15
* add explicit frame to qr code
* update library
* Revert "add explicit frame to qr code"
This reverts commit 95c7d31e47b3da39b5985cd57638885c45b77de1.
* remove comment
* fix pasteboardHasURLs, disable paste button based on it
* align help texts with changed button names
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
* update library
* Revert "fix pasteboardHasURLs, disable paste button based on it"
This reverts commit 46f63572e90dbf460faab9ce694181209712bd00.
* remove unused var
* restore disabled
* export localizations
---------
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
Co-authored-by: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
2023-12-29 16:29:49 +04:00
|
|
|
}
|