search add
This commit is contained in:
parent
ebb34b672a
commit
32dd59e635
@ -1,8 +1,7 @@
|
|||||||
//
|
|
||||||
// User.swift
|
|
||||||
// volnahub (iOS)
|
|
||||||
//
|
|
||||||
// Created by cheykrym on 09/06/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
struct User: Identifiable, Decodable {
|
||||||
|
let id: String
|
||||||
|
let username: String
|
||||||
|
let email: String
|
||||||
|
}
|
||||||
41
Shared/ViewModels/SearchViewModel.swift
Normal file
41
Shared/ViewModels/SearchViewModel.swift
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
class SearchViewModel: ObservableObject {
|
||||||
|
@Published var searchText = ""
|
||||||
|
@Published var users = [User]()
|
||||||
|
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
init() {
|
||||||
|
$searchText
|
||||||
|
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
|
||||||
|
.removeDuplicates()
|
||||||
|
.flatMap { query -> AnyPublisher<[User], Error> in
|
||||||
|
if query.isEmpty {
|
||||||
|
return Just([])
|
||||||
|
.setFailureType(to: Error.self)
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
} else {
|
||||||
|
return self.searchUsers(query: query)
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.catch { _ in Just([]) } // При ошибке возвращаем пустой массив
|
||||||
|
.receive(on: RunLoop.main)
|
||||||
|
.assign(to: \.users, on: self)
|
||||||
|
.store(in: &cancellables)
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchUsers(query: String) -> Future<[User], Error> {
|
||||||
|
Future { promise in
|
||||||
|
// Имитация сетевого запроса
|
||||||
|
let mockUsers = [
|
||||||
|
User(id: "1", username: "testuser1", email: "test1@test.com"),
|
||||||
|
User(id: "2", username: "testuser2", email: "test2@test.com"),
|
||||||
|
User(id: "3", username: query, email: "test3@test.com")
|
||||||
|
]
|
||||||
|
promise(.success(mockUsers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,68 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SearchTab: View {
|
struct SearchTab: View {
|
||||||
|
@StateObject private var viewModel = SearchViewModel()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
VStack {
|
VStack {
|
||||||
Text("Поиск")
|
SearchBar(text: $viewModel.searchText)
|
||||||
.font(.largeTitle)
|
.padding(.top, 8)
|
||||||
.bold()
|
|
||||||
.padding()
|
List(viewModel.users) { user in
|
||||||
Spacer()
|
NavigationLink(destination: ProfileTab(viewModel: LoginViewModel())) { // Placeholder destination
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "person.crop.circle")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
.clipShape(Circle())
|
||||||
|
Text(user.username)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listStyle(PlainListStyle())
|
||||||
}
|
}
|
||||||
.navigationTitle("Поиск")
|
.navigationTitle("Поиск")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SearchBar: View {
|
||||||
|
@Binding var text: String
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack {
|
||||||
|
TextField("Поиск...", text: $text)
|
||||||
|
.padding(8)
|
||||||
|
.padding(.horizontal, 25)
|
||||||
|
.background(Color(.systemGray6))
|
||||||
|
.cornerRadius(8)
|
||||||
|
.overlay(
|
||||||
|
HStack {
|
||||||
|
Image(systemName: "magnifyingglass")
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||||
|
.padding(.leading, 8)
|
||||||
|
|
||||||
|
if !text.isEmpty {
|
||||||
|
Button(action: {
|
||||||
|
self.text = ""
|
||||||
|
}) {
|
||||||
|
Image(systemName: "multiply.circle.fill")
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
.padding(.trailing, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SearchTab_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
SearchTab()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */; };
|
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */; };
|
||||||
1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276102DF9247000D8BC53 /* CustomTextField.swift */; };
|
1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276102DF9247000D8BC53 /* CustomTextField.swift */; };
|
||||||
|
1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2302102E3050C60067BF4F /* SearchViewModel.swift */; };
|
||||||
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* yobbleApp.swift */; };
|
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* yobbleApp.swift */; };
|
||||||
1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
|
1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
|
||||||
1A7940902DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
|
1A7940902DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
|
||||||
@ -49,6 +50,7 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1A0276022DF909F900D8BC53 /* refreshtokenex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = refreshtokenex.swift; sourceTree = "<group>"; };
|
1A0276022DF909F900D8BC53 /* refreshtokenex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = refreshtokenex.swift; sourceTree = "<group>"; };
|
||||||
1A0276102DF9247000D8BC53 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
|
1A0276102DF9247000D8BC53 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
|
||||||
|
1A2302102E3050C60067BF4F /* SearchViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; };
|
||||||
1A79407A2DF77BC2002569DA /* yobbleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = yobbleApp.swift; sourceTree = "<group>"; };
|
1A79407A2DF77BC2002569DA /* yobbleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = yobbleApp.swift; sourceTree = "<group>"; };
|
||||||
1A79407B2DF77BC2002569DA /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
1A79407B2DF77BC2002569DA /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||||
1A79407C2DF77BC3002569DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
1A79407C2DF77BC3002569DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
@ -177,6 +179,7 @@
|
|||||||
1A79409E2DF77DBD002569DA /* ViewModels */ = {
|
1A79409E2DF77DBD002569DA /* ViewModels */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
1A2302102E3050C60067BF4F /* SearchViewModel.swift */,
|
||||||
1A7940A92DF77E05002569DA /* LoginViewModel.swift */,
|
1A7940A92DF77E05002569DA /* LoginViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModels;
|
path = ViewModels;
|
||||||
@ -387,6 +390,7 @@
|
|||||||
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */,
|
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */,
|
||||||
1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */,
|
1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */,
|
||||||
1A7940DE2DF7B0D7002569DA /* config.swift in Sources */,
|
1A7940DE2DF7B0D7002569DA /* config.swift in Sources */,
|
||||||
|
1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */,
|
||||||
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */,
|
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */,
|
||||||
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
|
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
|
||||||
1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
|
1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user