feat(Views): 增加 Search bar 到 explore page

增加 Search bar 到 explore page

Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
Ching 2023-05-03 02:15:57 +08:00
parent 62c6c6d2c5
commit 577643d9b1
7 changed files with 134 additions and 24 deletions

View File

@ -13,6 +13,8 @@
2492CC152A000EB10086C525 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2492CC142A000EB10086C525 /* Preview Assets.xcassets */; };
2492CC252A0023220086C525 /* FeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492CC242A0023220086C525 /* FeedView.swift */; };
2492CC282A0025DD0086C525 /* TweetRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492CC272A0025DD0086C525 /* TweetRowView.swift */; };
24A07CB02A017D3300F4ECA8 /* ExploreViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A07CAF2A017D3300F4ECA8 /* ExploreViewModel.swift */; };
24A07CB22A01869F00F4ECA8 /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A07CB12A01869F00F4ECA8 /* SearchBar.swift */; };
24A59AB42A002EB8009C9E3E /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59AB32A002EB8009C9E3E /* MainTabView.swift */; };
24A59ABA2A0030CB009C9E3E /* ExploreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59AB92A0030CB009C9E3E /* ExploreView.swift */; };
24A59ABC2A0030EC009C9E3E /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59ABB2A0030EC009C9E3E /* NotificationsView.swift */; };
@ -54,6 +56,8 @@
2492CC142A000EB10086C525 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2492CC242A0023220086C525 /* FeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedView.swift; sourceTree = "<group>"; };
2492CC272A0025DD0086C525 /* TweetRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TweetRowView.swift; sourceTree = "<group>"; };
24A07CAF2A017D3300F4ECA8 /* ExploreViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreViewModel.swift; sourceTree = "<group>"; };
24A07CB12A01869F00F4ECA8 /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
24A59AB32A002EB8009C9E3E /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
24A59AB92A0030CB009C9E3E /* ExploreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreView.swift; sourceTree = "<group>"; };
24A59ABB2A0030EC009C9E3E /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
@ -142,10 +146,10 @@
2492CC1B2A00228F0086C525 /* Core */ = {
isa = PBXGroup;
children = (
2492CC212A0022C30086C525 /* Components */,
24A59AE02A00EEE8009C9E3E /* Authentication */,
24A59AD72A00DB49009C9E3E /* UploadTweet */,
24A59ACA2A00BDA1009C9E3E /* SideMenu */,
2492CC212A0022C30086C525 /* Components */,
24A59AB82A00308E009C9E3E /* Profile */,
24A59AB72A00305E009C9E3E /* Explore */,
24A59AB62A00305C009C9E3E /* Notifications */,
@ -198,6 +202,7 @@
24A59ADE2A00DCC2009C9E3E /* TextArea.swift */,
24A59AE72A00F106009C9E3E /* RoundedShape.swift */,
24A59AE92A00F672009C9E3E /* CustomInputField.swift */,
24A07CB12A01869F00F4ECA8 /* SearchBar.swift */,
);
path = Components;
sourceTree = "<group>";
@ -286,6 +291,7 @@
24A59AC52A00BA3A009C9E3E /* ViewModels */ = {
isa = PBXGroup;
children = (
24A07CAF2A017D3300F4ECA8 /* ExploreViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
@ -494,10 +500,12 @@
2492CC252A0023220086C525 /* FeedView.swift in Sources */,
24A59ACE2A00BDCB009C9E3E /* SideMenuView.swift in Sources */,
24FA4D992A012A5D002D202A /* ProfilePhotoSelectorView.swift in Sources */,
24A07CB02A017D3300F4ECA8 /* ExploreViewModel.swift in Sources */,
2492CC0D2A000EB00086C525 /* dudu_tweetApp.swift in Sources */,
24A59ABA2A0030CB009C9E3E /* ExploreView.swift in Sources */,
24A59AD22A00BE14009C9E3E /* SideMenuViewModel.swift in Sources */,
24A59ADF2A00DCC2009C9E3E /* TextArea.swift in Sources */,
24A07CB22A01869F00F4ECA8 /* SearchBar.swift in Sources */,
24A59AD62A00CA82009C9E3E /* SideMenuOptionRowView.swift in Sources */,
24A59AE42A00EF1F009C9E3E /* LoginView.swift in Sources */,
24A59AE62A00EF3A009C9E3E /* RegistrationView.swift in Sources */,

View File

@ -0,0 +1,40 @@
//
// SearchBar.swift
// dudu-tweet
//
// Created by ching on 2023/5/3.
//
import SwiftUI
struct SearchBar: View {
@Binding var text: String
var body: some View {
HStack {
TextField("Search...", text: $text)
.padding(8)
.padding(.horizontal, 24)
.background(Color(.systemGray6))
.cornerRadius(8)
.overlay(
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
.padding(.leading, 8)
}
)
}
.padding(.horizontal, 4)
}
}
struct SearchBar_Previews: PreviewProvider {
static var previews: some View {
SearchBar(text: .constant(""))
.previewLayout(.sizeThatFits)
}
}

View File

@ -6,17 +6,23 @@
//
import SwiftUI
import Kingfisher
struct UserRowView: View {
let user: User
var body: some View {
HStack(spacing: 12) {
Circle()
.frame(width: 48, height: 48)
KFImage(URL(string: user.profileImageUrl))
.resizable()
.scaledToFill()
.clipShape(Circle())
.frame(width: 56, height: 56)
VStack(alignment: .leading, spacing: 4) {
Text("Lith")
Text(user.username)
.font(.subheadline).bold()
.foregroundColor(.black)
Text("李四")
Text(user.fullname)
.font(.subheadline)
.foregroundColor(.gray)
}
@ -27,8 +33,8 @@ struct UserRowView: View {
}
}
struct UserRowView_Previews: PreviewProvider {
static var previews: some View {
UserRowView()
}
}
//struct UserRowView_Previews: PreviewProvider {
// static var previews: some View {
//// UserRowView()
// }
//}

View File

@ -0,0 +1,40 @@
//
// ExploreViewModel.swift
// dudu-tweet
//
// Created by ching on 2023/5/3.
//
import Foundation
class ExploreViewModel: ObservableObject {
@Published var users = [User]()
@Published var searchText = ""
var searchableUsers: [User] {
if searchText.isEmpty {
return users
} else {
let lowercasedQuery = searchText.lowercased()
return users.filter({
$0.username.contains(lowercasedQuery) ||
$0.fullname.lowercased().contains(lowercasedQuery)
})
}
}
let service = UserService()
init() {
fetchUsers()
}
func fetchUsers() {
service.fetchUsers { users in
self.users = users
print("DEBUG: users \(users)")
}
}
}

View File

@ -8,16 +8,19 @@
import SwiftUI
struct ExploreView: View {
@ObservedObject var viewModel = ExploreViewModel()
var body: some View {
NavigationView {
VStack {
SearchBar(text: $viewModel.searchText)
.padding()
ScrollView {
LazyVStack {
ForEach(0...25, id: \.self) { _ in
ForEach(viewModel.searchableUsers) { user in
NavigationLink {
// ProfileView()
ProfileView(user: user)
} label: {
UserRowView()
UserRowView(user: user)
}
}
@ -28,7 +31,6 @@ struct ExploreView: View {
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct ExploreView_Previews: PreviewProvider {
static var previews: some View {

View File

@ -21,4 +21,18 @@ struct UserService {
completion(user)
}
}
func fetchUsers(completion: @escaping ([User]) -> Void) {
// var users = [User]()
Firestore.firestore().collection("users")
.getDocuments { snapshot, _ in
guard let documents = snapshot?.documents else { return }
// for document in documents {
// guard let user = try? document.data(as: User.self) else { return }
// users.append(user)
// }
let users = documents.compactMap({ try? $0.data(as: User.self) })
completion(users)
}
}
}