feat(Views): 增加 Search bar 到 explore page
增加 Search bar 到 explore page Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
parent
62c6c6d2c5
commit
577643d9b1
@ -13,6 +13,8 @@
|
|||||||
2492CC152A000EB10086C525 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2492CC142A000EB10086C525 /* Preview Assets.xcassets */; };
|
2492CC152A000EB10086C525 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2492CC142A000EB10086C525 /* Preview Assets.xcassets */; };
|
||||||
2492CC252A0023220086C525 /* FeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492CC242A0023220086C525 /* FeedView.swift */; };
|
2492CC252A0023220086C525 /* FeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492CC242A0023220086C525 /* FeedView.swift */; };
|
||||||
2492CC282A0025DD0086C525 /* TweetRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492CC272A0025DD0086C525 /* TweetRowView.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 */; };
|
24A59AB42A002EB8009C9E3E /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59AB32A002EB8009C9E3E /* MainTabView.swift */; };
|
||||||
24A59ABA2A0030CB009C9E3E /* ExploreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59AB92A0030CB009C9E3E /* ExploreView.swift */; };
|
24A59ABA2A0030CB009C9E3E /* ExploreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59AB92A0030CB009C9E3E /* ExploreView.swift */; };
|
||||||
24A59ABC2A0030EC009C9E3E /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A59ABB2A0030EC009C9E3E /* NotificationsView.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
24A59ABB2A0030EC009C9E3E /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = "<group>"; };
|
||||||
@ -142,10 +146,10 @@
|
|||||||
2492CC1B2A00228F0086C525 /* Core */ = {
|
2492CC1B2A00228F0086C525 /* Core */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
2492CC212A0022C30086C525 /* Components */,
|
||||||
24A59AE02A00EEE8009C9E3E /* Authentication */,
|
24A59AE02A00EEE8009C9E3E /* Authentication */,
|
||||||
24A59AD72A00DB49009C9E3E /* UploadTweet */,
|
24A59AD72A00DB49009C9E3E /* UploadTweet */,
|
||||||
24A59ACA2A00BDA1009C9E3E /* SideMenu */,
|
24A59ACA2A00BDA1009C9E3E /* SideMenu */,
|
||||||
2492CC212A0022C30086C525 /* Components */,
|
|
||||||
24A59AB82A00308E009C9E3E /* Profile */,
|
24A59AB82A00308E009C9E3E /* Profile */,
|
||||||
24A59AB72A00305E009C9E3E /* Explore */,
|
24A59AB72A00305E009C9E3E /* Explore */,
|
||||||
24A59AB62A00305C009C9E3E /* Notifications */,
|
24A59AB62A00305C009C9E3E /* Notifications */,
|
||||||
@ -198,6 +202,7 @@
|
|||||||
24A59ADE2A00DCC2009C9E3E /* TextArea.swift */,
|
24A59ADE2A00DCC2009C9E3E /* TextArea.swift */,
|
||||||
24A59AE72A00F106009C9E3E /* RoundedShape.swift */,
|
24A59AE72A00F106009C9E3E /* RoundedShape.swift */,
|
||||||
24A59AE92A00F672009C9E3E /* CustomInputField.swift */,
|
24A59AE92A00F672009C9E3E /* CustomInputField.swift */,
|
||||||
|
24A07CB12A01869F00F4ECA8 /* SearchBar.swift */,
|
||||||
);
|
);
|
||||||
path = Components;
|
path = Components;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -286,6 +291,7 @@
|
|||||||
24A59AC52A00BA3A009C9E3E /* ViewModels */ = {
|
24A59AC52A00BA3A009C9E3E /* ViewModels */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
24A07CAF2A017D3300F4ECA8 /* ExploreViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModels;
|
path = ViewModels;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -494,10 +500,12 @@
|
|||||||
2492CC252A0023220086C525 /* FeedView.swift in Sources */,
|
2492CC252A0023220086C525 /* FeedView.swift in Sources */,
|
||||||
24A59ACE2A00BDCB009C9E3E /* SideMenuView.swift in Sources */,
|
24A59ACE2A00BDCB009C9E3E /* SideMenuView.swift in Sources */,
|
||||||
24FA4D992A012A5D002D202A /* ProfilePhotoSelectorView.swift in Sources */,
|
24FA4D992A012A5D002D202A /* ProfilePhotoSelectorView.swift in Sources */,
|
||||||
|
24A07CB02A017D3300F4ECA8 /* ExploreViewModel.swift in Sources */,
|
||||||
2492CC0D2A000EB00086C525 /* dudu_tweetApp.swift in Sources */,
|
2492CC0D2A000EB00086C525 /* dudu_tweetApp.swift in Sources */,
|
||||||
24A59ABA2A0030CB009C9E3E /* ExploreView.swift in Sources */,
|
24A59ABA2A0030CB009C9E3E /* ExploreView.swift in Sources */,
|
||||||
24A59AD22A00BE14009C9E3E /* SideMenuViewModel.swift in Sources */,
|
24A59AD22A00BE14009C9E3E /* SideMenuViewModel.swift in Sources */,
|
||||||
24A59ADF2A00DCC2009C9E3E /* TextArea.swift in Sources */,
|
24A59ADF2A00DCC2009C9E3E /* TextArea.swift in Sources */,
|
||||||
|
24A07CB22A01869F00F4ECA8 /* SearchBar.swift in Sources */,
|
||||||
24A59AD62A00CA82009C9E3E /* SideMenuOptionRowView.swift in Sources */,
|
24A59AD62A00CA82009C9E3E /* SideMenuOptionRowView.swift in Sources */,
|
||||||
24A59AE42A00EF1F009C9E3E /* LoginView.swift in Sources */,
|
24A59AE42A00EF1F009C9E3E /* LoginView.swift in Sources */,
|
||||||
24A59AE62A00EF3A009C9E3E /* RegistrationView.swift in Sources */,
|
24A59AE62A00EF3A009C9E3E /* RegistrationView.swift in Sources */,
|
||||||
|
|||||||
Binary file not shown.
40
dudu-tweet/dudu-tweet/Core/Components/SearchBar.swift
Normal file
40
dudu-tweet/dudu-tweet/Core/Components/SearchBar.swift
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -6,17 +6,23 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
struct UserRowView: View {
|
struct UserRowView: View {
|
||||||
|
let user: User
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
Circle()
|
KFImage(URL(string: user.profileImageUrl))
|
||||||
.frame(width: 48, height: 48)
|
.resizable()
|
||||||
|
.scaledToFill()
|
||||||
|
.clipShape(Circle())
|
||||||
|
.frame(width: 56, height: 56)
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
Text("Lith")
|
Text(user.username)
|
||||||
.font(.subheadline).bold()
|
.font(.subheadline).bold()
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
Text("李四")
|
Text(user.fullname)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
@ -27,8 +33,8 @@ struct UserRowView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UserRowView_Previews: PreviewProvider {
|
//struct UserRowView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
// static var previews: some View {
|
||||||
UserRowView()
|
//// UserRowView()
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@ -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)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,16 +8,19 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ExploreView: View {
|
struct ExploreView: View {
|
||||||
|
@ObservedObject var viewModel = ExploreViewModel()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
|
||||||
VStack {
|
VStack {
|
||||||
|
SearchBar(text: $viewModel.searchText)
|
||||||
|
.padding()
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
ForEach(0...25, id: \.self) { _ in
|
ForEach(viewModel.searchableUsers) { user in
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
// ProfileView()
|
ProfileView(user: user)
|
||||||
} label: {
|
} label: {
|
||||||
UserRowView()
|
UserRowView(user: user)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -27,7 +30,6 @@ struct ExploreView: View {
|
|||||||
.navigationTitle("Explore")
|
.navigationTitle("Explore")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExploreView_Previews: PreviewProvider {
|
struct ExploreView_Previews: PreviewProvider {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import Firebase
|
|||||||
import FirebaseFirestoreSwift
|
import FirebaseFirestoreSwift
|
||||||
|
|
||||||
struct UserService {
|
struct UserService {
|
||||||
func fetchUser(withUid uid: String, completion: @escaping(User) -> Void) {
|
func fetchUser(withUid uid: String, completion: @escaping (User) -> Void) {
|
||||||
print("DEBUG: Fetching user info..")
|
print("DEBUG: Fetching user info..")
|
||||||
Firestore.firestore().collection("users")
|
Firestore.firestore().collection("users")
|
||||||
.document(uid)
|
.document(uid)
|
||||||
@ -21,4 +21,18 @@ struct UserService {
|
|||||||
completion(user)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user