diff --git a/dudu-tweet/dudu-tweet.xcodeproj/project.pbxproj b/dudu-tweet/dudu-tweet.xcodeproj/project.pbxproj index f82785c..f6ad708 100644 --- a/dudu-tweet/dudu-tweet.xcodeproj/project.pbxproj +++ b/dudu-tweet/dudu-tweet.xcodeproj/project.pbxproj @@ -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 = ""; }; 2492CC242A0023220086C525 /* FeedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedView.swift; sourceTree = ""; }; 2492CC272A0025DD0086C525 /* TweetRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TweetRowView.swift; sourceTree = ""; }; + 24A07CAF2A017D3300F4ECA8 /* ExploreViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreViewModel.swift; sourceTree = ""; }; + 24A07CB12A01869F00F4ECA8 /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = ""; }; 24A59AB32A002EB8009C9E3E /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = ""; }; 24A59AB92A0030CB009C9E3E /* ExploreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreView.swift; sourceTree = ""; }; 24A59ABB2A0030EC009C9E3E /* NotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsView.swift; sourceTree = ""; }; @@ -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 = ""; @@ -286,6 +291,7 @@ 24A59AC52A00BA3A009C9E3E /* ViewModels */ = { isa = PBXGroup; children = ( + 24A07CAF2A017D3300F4ECA8 /* ExploreViewModel.swift */, ); path = ViewModels; sourceTree = ""; @@ -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 */, diff --git a/dudu-tweet/dudu-tweet.xcodeproj/project.xcworkspace/xcuserdata/ching.xcuserdatad/UserInterfaceState.xcuserstate b/dudu-tweet/dudu-tweet.xcodeproj/project.xcworkspace/xcuserdata/ching.xcuserdatad/UserInterfaceState.xcuserstate index 12d758b..128a06c 100644 Binary files a/dudu-tweet/dudu-tweet.xcodeproj/project.xcworkspace/xcuserdata/ching.xcuserdatad/UserInterfaceState.xcuserstate and b/dudu-tweet/dudu-tweet.xcodeproj/project.xcworkspace/xcuserdata/ching.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/dudu-tweet/dudu-tweet/Core/Components/SearchBar.swift b/dudu-tweet/dudu-tweet/Core/Components/SearchBar.swift new file mode 100644 index 0000000..f333822 --- /dev/null +++ b/dudu-tweet/dudu-tweet/Core/Components/SearchBar.swift @@ -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) + } +} + diff --git a/dudu-tweet/dudu-tweet/Core/Components/Users/UserRowView.swift b/dudu-tweet/dudu-tweet/Core/Components/Users/UserRowView.swift index 3a807a3..0825ae4 100644 --- a/dudu-tweet/dudu-tweet/Core/Components/Users/UserRowView.swift +++ b/dudu-tweet/dudu-tweet/Core/Components/Users/UserRowView.swift @@ -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() +// } +//} diff --git a/dudu-tweet/dudu-tweet/Core/Explore/ViewModels/ExploreViewModel.swift b/dudu-tweet/dudu-tweet/Core/Explore/ViewModels/ExploreViewModel.swift new file mode 100644 index 0000000..6fd046a --- /dev/null +++ b/dudu-tweet/dudu-tweet/Core/Explore/ViewModels/ExploreViewModel.swift @@ -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)") + } + } +} diff --git a/dudu-tweet/dudu-tweet/Core/Explore/Views/ExploreView.swift b/dudu-tweet/dudu-tweet/Core/Explore/Views/ExploreView.swift index 8df4b27..89634d8 100644 --- a/dudu-tweet/dudu-tweet/Core/Explore/Views/ExploreView.swift +++ b/dudu-tweet/dudu-tweet/Core/Explore/Views/ExploreView.swift @@ -8,25 +8,27 @@ import SwiftUI struct ExploreView: View { + @ObservedObject var viewModel = ExploreViewModel() + var body: some View { - NavigationView { - VStack { - ScrollView { - LazyVStack { - ForEach(0...25, id: \.self) { _ in - NavigationLink { -// ProfileView() - } label: { - UserRowView() - } - + VStack { + SearchBar(text: $viewModel.searchText) + .padding() + ScrollView { + LazyVStack { + ForEach(viewModel.searchableUsers) { user in + NavigationLink { + ProfileView(user: user) + } label: { + UserRowView(user: user) } + } } } - .navigationTitle("Explore") - .navigationBarTitleDisplayMode(.inline) } + .navigationTitle("Explore") + .navigationBarTitleDisplayMode(.inline) } } diff --git a/dudu-tweet/dudu-tweet/Service/UserService.swift b/dudu-tweet/dudu-tweet/Service/UserService.swift index d05b0d5..98477f7 100644 --- a/dudu-tweet/dudu-tweet/Service/UserService.swift +++ b/dudu-tweet/dudu-tweet/Service/UserService.swift @@ -9,7 +9,7 @@ import Firebase import FirebaseFirestoreSwift 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..") Firestore.firestore().collection("users") .document(uid) @@ -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) + } + } }