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

View File

@ -11,6 +11,7 @@ struct ChatsTab: View {
var currentUserId: String? = nil var currentUserId: String? = nil
@StateObject private var viewModel = PrivateChatsViewModel() @StateObject private var viewModel = PrivateChatsViewModel()
@State private var selectedChatId: String? @State private var selectedChatId: String?
@State private var searchText: String = ""
var body: some View { var body: some View {
content content
@ -38,6 +39,14 @@ struct ChatsTab: View {
private var chatList: some View { private var chatList: some View {
List { List {
VStack(spacing: 0) {
searchBar
.padding(.horizontal, 16)
.padding(.top, 8)
.padding(.bottom, 8)
}
.background(Color(UIColor.systemBackground))
if let message = viewModel.errorMessage { if let message = viewModel.errorMessage {
Section { Section {
HStack(alignment: .top, spacing: 8) { HStack(alignment: .top, spacing: 8) {
@ -57,47 +66,126 @@ struct ChatsTab: View {
.listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16)) .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
} }
ForEach(viewModel.chats) { chat in if filteredChats.isEmpty && isSearching {
Button { Section {
selectedChatId = chat.chatId emptySearchResultView
} label: {
ChatRowView(chat: chat, currentUserId: currentUserId)
.contentShape(Rectangle())
} }
.buttonStyle(.plain) .listRowInsets(EdgeInsets(top: 24, leading: 16, bottom: 24, trailing: 16))
.contextMenu { .listRowSeparator(.hidden)
Button(action: {}) { } else {
Label(NSLocalizedString("Закрепить (скоро)", comment: ""), systemImage: "pin") 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: {}) { Button(action: {}) {
Label(NSLocalizedString("Без звука (скоро)", comment: ""), systemImage: "speaker.slash") Label(NSLocalizedString("Без звука (скоро)", comment: ""), systemImage: "speaker.slash")
} }
Button(role: .destructive, action: {}) { Button(role: .destructive, action: {}) {
Label(NSLocalizedString("Удалить чат (скоро)", comment: ""), systemImage: "trash") Label(NSLocalizedString("Удалить чат (скоро)", comment: ""), systemImage: "trash")
}
} }
} .background(
.background( NavigationLink(
NavigationLink( destination: ChatPlaceholderView(chat: chat),
destination: ChatPlaceholderView(chat: chat), tag: chat.chatId,
tag: chat.chatId, selection: $selectedChatId
selection: $selectedChatId ) {
) { EmptyView()
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 loadingMoreRow
} }
} }
.listStyle(.plain) .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 { private var loadingState: some View {