feat(ViewModel): 增加 profile view model,获取 profile 页的 tweets
增加 profile view model,获取 profile 页的 tweets Signed-off-by: Ching <loooching@gmail.com>
This commit is contained in:
parent
9d237961b6
commit
5b7648e6e7
@ -19,6 +19,7 @@
|
||||
24A07CB62A020FF900F4ECA8 /* UploadTweetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A07CB52A020FF900F4ECA8 /* UploadTweetViewModel.swift */; };
|
||||
24A07CB82A02173400F4ECA8 /* FeedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A07CB72A02173400F4ECA8 /* FeedViewModel.swift */; };
|
||||
24A07CBA2A02186500F4ECA8 /* Tweet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A07CB92A02186500F4ECA8 /* Tweet.swift */; };
|
||||
24A07CBC2A022B2000F4ECA8 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A07CBB2A022B2000F4ECA8 /* ProfileViewModel.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 */; };
|
||||
@ -66,6 +67,7 @@
|
||||
24A07CB52A020FF900F4ECA8 /* UploadTweetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadTweetViewModel.swift; sourceTree = "<group>"; };
|
||||
24A07CB72A02173400F4ECA8 /* FeedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedViewModel.swift; sourceTree = "<group>"; };
|
||||
24A07CB92A02186500F4ECA8 /* Tweet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tweet.swift; sourceTree = "<group>"; };
|
||||
24A07CBB2A022B2000F4ECA8 /* ProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewModel.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>"; };
|
||||
@ -295,6 +297,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
24A59AC32A003A52009C9E3E /* TwewtFilterViewModel.swift */,
|
||||
24A07CBB2A022B2000F4ECA8 /* ProfileViewModel.swift */,
|
||||
);
|
||||
path = ViewModels;
|
||||
sourceTree = "<group>";
|
||||
@ -534,6 +537,7 @@
|
||||
24A59AB42A002EB8009C9E3E /* MainTabView.swift in Sources */,
|
||||
24A59ABC2A0030EC009C9E3E /* NotificationsView.swift in Sources */,
|
||||
24A59AD42A00C07D009C9E3E /* UserStatsView.swift in Sources */,
|
||||
24A07CBC2A022B2000F4ECA8 /* ProfileViewModel.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
Binary file not shown.
@ -37,7 +37,6 @@ extension ContentView {
|
||||
ZStack(alignment: .topLeading) {
|
||||
MainTabView()
|
||||
.toolbar(showMenu ? .hidden : .visible)
|
||||
|
||||
if showMenu {
|
||||
ZStack {
|
||||
Color(.black)
|
||||
@ -55,8 +54,6 @@ extension ContentView {
|
||||
.offset(x: showMenu ? 0: -300, y: 0)
|
||||
.background(showMenu ? Color.white: Color.clear)
|
||||
}
|
||||
.navigationTitle("Home")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
if let user = viewModel.currentUser {
|
||||
|
||||
@ -19,7 +19,6 @@ class AuthViewModel: ObservableObject {
|
||||
init() {
|
||||
self.userSession = Auth.auth().currentUser
|
||||
self.fetchUser()
|
||||
print("DEBUG: user session is \(self.userSession?.uid)")
|
||||
}
|
||||
|
||||
func login(withEmail email: String, password: String) {
|
||||
|
||||
@ -9,7 +9,7 @@ import SwiftUI
|
||||
|
||||
struct ExploreView: View {
|
||||
@ObservedObject var viewModel = ExploreViewModel()
|
||||
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
SearchBar(text: $viewModel.searchText)
|
||||
@ -18,17 +18,14 @@ struct ExploreView: View {
|
||||
LazyVStack {
|
||||
ForEach(viewModel.searchableUsers) { user in
|
||||
NavigationLink {
|
||||
ProfileView(user: user)
|
||||
ProfileView(user: user)
|
||||
} label: {
|
||||
UserRowView(user: user)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("Explore")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import SwiftUI
|
||||
struct FeedView: View {
|
||||
@State private var showNewTweetView = false
|
||||
@ObservedObject var viewModel = FeedViewModel()
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
ScrollView {
|
||||
@ -20,7 +20,7 @@ struct FeedView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button {
|
||||
showNewTweetView.toggle()
|
||||
} label: {
|
||||
@ -37,7 +37,6 @@ struct FeedView: View {
|
||||
.fullScreenCover(isPresented: $showNewTweetView) {
|
||||
NewTweetView()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,37 +9,56 @@ import SwiftUI
|
||||
|
||||
struct MainTabView: View {
|
||||
@State private var selectedIndex: Int = 0
|
||||
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: $selectedIndex) {
|
||||
FeedView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 0
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "house")
|
||||
}.tag(0)
|
||||
ExploreView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 1
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "magnifyingglass")
|
||||
}.tag(1)
|
||||
NotificationsView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 2
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "bell")
|
||||
}.tag(2)
|
||||
MessagesView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 3
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "envelope")
|
||||
}.tag(3)
|
||||
NavigationView {
|
||||
TabView(selection: $selectedIndex) {
|
||||
FeedView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 0
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "house")
|
||||
}.tag(0)
|
||||
ExploreView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 1
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "magnifyingglass")
|
||||
}.tag(1)
|
||||
NotificationsView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 2
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "bell")
|
||||
}.tag(2)
|
||||
MessagesView()
|
||||
.onTapGesture {
|
||||
self.selectedIndex = 3
|
||||
}
|
||||
.tabItem {
|
||||
Image(systemName: "envelope")
|
||||
}.tag(3)
|
||||
}
|
||||
}
|
||||
.navigationTitle(title(for: selectedIndex))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
func title(for tab: Int) -> String {
|
||||
switch tab {
|
||||
case 0:
|
||||
return "Home"
|
||||
case 1:
|
||||
return "Explore"
|
||||
case 2:
|
||||
return "Notification"
|
||||
case 3:
|
||||
return "Message"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
//
|
||||
// ProfileViewModel.swift
|
||||
// dudu-tweet
|
||||
//
|
||||
// Created by ching on 2023/5/3.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
class ProfileViewModel: ObservableObject {
|
||||
@Published var tweets = [Tweet]()
|
||||
private let service = TweetService()
|
||||
let user: User
|
||||
|
||||
init(user: User) {
|
||||
self.user = user
|
||||
self.fetchUserTweet()
|
||||
}
|
||||
|
||||
func fetchUserTweet() {
|
||||
guard let uid = user.id else { return }
|
||||
service.fetchTweets(forUid: uid) { tweets in
|
||||
self.tweets = tweets
|
||||
for i in 0 ..< tweets.count {
|
||||
self.tweets[i].user = self.user
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,12 +12,12 @@ struct ProfileView: View {
|
||||
@State private var selectedFilter: TweetFilterViewModel = .tweets
|
||||
// @Environment(\.presentationMode) var mode // 用来从explore 页面跳转过来之后跳转回去
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
private let user: User
|
||||
@ObservedObject var viewModel: ProfileViewModel
|
||||
|
||||
@Namespace var animation
|
||||
|
||||
init(user: User) {
|
||||
self.user = user
|
||||
self.viewModel = ProfileViewModel(user: user)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
@ -65,7 +65,7 @@ extension ProfileView {
|
||||
.offset(x: 16, y: -4)
|
||||
}
|
||||
|
||||
KFImage(URL(string: user.profileImageUrl))
|
||||
KFImage(URL(string: viewModel.user.profileImageUrl))
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.clipShape(Circle())
|
||||
@ -100,12 +100,12 @@ extension ProfileView {
|
||||
var userInfoDetails: some View {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(user.fullname)
|
||||
Text(viewModel.user.fullname)
|
||||
.font(.title2).bold()
|
||||
Image(systemName: "checkmark.seal.fill")
|
||||
.foregroundColor(Color(.systemBlue))
|
||||
}
|
||||
Text("@\(user.username)")
|
||||
Text("@\(viewModel.user.username)")
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.gray)
|
||||
Text("一个普通人")
|
||||
@ -165,8 +165,8 @@ extension ProfileView {
|
||||
var tweetsView: some View {
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
ForEach(0...9, id: \.self) { _ in
|
||||
// TweetRowView()
|
||||
ForEach(viewModel.tweets) { tweet in
|
||||
TweetRowView(tweet: tweet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,12 +30,25 @@ struct TweetService {
|
||||
|
||||
|
||||
func fetchTweets(completion: @escaping([Tweet]) -> Void) {
|
||||
Firestore.firestore().collection("tweets").getDocuments { snapshot, _ in
|
||||
Firestore.firestore().collection("tweets")
|
||||
.order(by: "timestamp", descending: true)
|
||||
.getDocuments { snapshot, _ in
|
||||
guard let documents = snapshot?.documents else { return }
|
||||
|
||||
let tweets = documents.compactMap({ try? $0.data(as: Tweet.self) })
|
||||
completion(tweets)
|
||||
}
|
||||
}
|
||||
|
||||
func fetchTweets(forUid uid: String, completion: @escaping([Tweet]) -> Void) {
|
||||
Firestore.firestore().collection("tweets")
|
||||
.whereField("uid", isEqualTo: uid)
|
||||
.getDocuments { snapshot, _ in
|
||||
guard let documents = snapshot?.documents else { return }
|
||||
|
||||
let tweets = documents.compactMap({ try? $0.data(as: Tweet.self) })
|
||||
completion(tweets.sorted(by: { $0.timestamp.dateValue() > $1.timestamp.dateValue()}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user