add search

This commit is contained in:
cheykrym 2025-10-07 03:21:11 +03:00
parent 58750dee48
commit 36759022a1
2 changed files with 125 additions and 28 deletions

View File

@ -718,6 +718,9 @@
}
}
}
},
"Ничего не найдено" : {
},
"Новый пароль" : {
"comment" : "Новый пароль",
@ -944,6 +947,9 @@
}
}
}
},
"Поиск" : {
},
"Пока что у вас нет чатов" : {
"localizations" : {
@ -977,6 +983,9 @@
}
}
}
},
"Попробуйте изменить запрос поиска." : {
},
"Приглашение достигло лимита использования." : {
"localizations" : {

View File

@ -11,6 +11,7 @@ struct ChatsTab: View {
var currentUserId: String? = nil
@StateObject private var viewModel = PrivateChatsViewModel()
@State private var selectedChatId: String?
@State private var searchText: String = ""
var body: some View {
content
@ -38,6 +39,14 @@ struct ChatsTab: View {
private var chatList: some View {
List {
VStack(spacing: 0) {
searchBar
.padding(.horizontal, 16)
.padding(.top, 8)
.padding(.bottom, 8)
}
.background(Color(UIColor.systemBackground))
if let message = viewModel.errorMessage {
Section {
HStack(alignment: .top, spacing: 8) {
@ -57,47 +66,126 @@ struct ChatsTab: View {
.listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
}
ForEach(viewModel.chats) { chat in
Button {
selectedChatId = chat.chatId
} label: {
ChatRowView(chat: chat, currentUserId: currentUserId)
.contentShape(Rectangle())
if filteredChats.isEmpty && isSearching {
Section {
emptySearchResultView
}
.buttonStyle(.plain)
.contextMenu {
Button(action: {}) {
Label(NSLocalizedString("Закрепить (скоро)", comment: ""), systemImage: "pin")
.listRowInsets(EdgeInsets(top: 24, leading: 16, bottom: 24, trailing: 16))
.listRowSeparator(.hidden)
} else {
ForEach(filteredChats) { chat in
Button {
selectedChatId = chat.chatId
} label: {
ChatRowView(chat: chat, currentUserId: currentUserId)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.contextMenu {
Button(action: {}) {
Label(NSLocalizedString("Закрепить (скоро)", comment: ""), systemImage: "pin")
}
Button(action: {}) {
Label(NSLocalizedString("Без звука (скоро)", comment: ""), systemImage: "speaker.slash")
}
Button(action: {}) {
Label(NSLocalizedString("Без звука (скоро)", comment: ""), systemImage: "speaker.slash")
}
Button(role: .destructive, action: {}) {
Label(NSLocalizedString("Удалить чат (скоро)", comment: ""), systemImage: "trash")
Button(role: .destructive, action: {}) {
Label(NSLocalizedString("Удалить чат (скоро)", comment: ""), systemImage: "trash")
}
}
}
.background(
NavigationLink(
destination: ChatPlaceholderView(chat: chat),
tag: chat.chatId,
selection: $selectedChatId
) {
EmptyView()
.background(
NavigationLink(
destination: ChatPlaceholderView(chat: chat),
tag: chat.chatId,
selection: $selectedChatId
) {
EmptyView()
}
.hidden()
)
.onAppear {
guard !isSearching else { return }
viewModel.loadMoreIfNeeded(currentItem: chat)
}
.hidden()
)
.onAppear {
viewModel.loadMoreIfNeeded(currentItem: chat)
}
}
if viewModel.isLoadingMore {
if viewModel.isLoadingMore && !isSearching {
loadingMoreRow
}
}
.listStyle(.plain)
// .safeAreaInset(edge: .top) {
// VStack(spacing: 0) {
// searchBar
// .padding(.horizontal, 16)
// .padding(.top, 8)
// .padding(.bottom, 8)
// Divider()
// }
// .background(Color(UIColor.systemBackground))
// }
}
private var searchBar: some View {
HStack(spacing: 8) {
Image(systemName: "magnifyingglass")
.foregroundColor(.secondary)
TextField(NSLocalizedString("Поиск", comment: ""), text: $searchText)
.textFieldStyle(.plain)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
if !searchText.isEmpty {
Button(action: { searchText = "" }) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
}
}
.padding(.horizontal, 12)
.padding(.vertical, 10)
.background(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.fill(Color(UIColor.secondarySystemBackground))
)
}
private var isSearching: Bool {
!searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
private var filteredChats: [PrivateChatListItem] {
let trimmedQuery = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmedQuery.isEmpty else { return viewModel.chats }
let lowercasedQuery = trimmedQuery.lowercased()
return viewModel.chats.filter { chat in
let searchableValues = [
chat.chatData?.customName,
chat.chatData?.fullName,
chat.chatData?.login,
chat.lastMessage?.content
]
return searchableValues
.compactMap { $0?.lowercased() }
.contains(where: { $0.contains(lowercasedQuery) })
}
}
private var emptySearchResultView: some View {
VStack(spacing: 8) {
Image(systemName: "text.magnifyingglass")
.font(.system(size: 40))
.foregroundColor(.secondary)
Text(NSLocalizedString("Ничего не найдено", comment: ""))
.font(.headline)
Text(NSLocalizedString("Попробуйте изменить запрос поиска.", comment: ""))
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
}
.frame(maxWidth: .infinity)
}
private var loadingState: some View {