I am trying to achieve a view with users in a Vgrid, when a user's profile picture is tapped it should go directly to his/her profile. I have tried a lot of ways to make it work any help is needed.
When i tap on any user it goes to the first user in my firebase collections and does not navigate to the user's profile i tapped.
The PeepsGridView() in the VGrid works correctly and user searches and matched correcly it just the issue with the correct profile for each user tapped.
Below is the View with the Vgrid and the Navigation link to the profile view:
struct PeopleView: View {
@ObservedObject var peoplesViewModel = PeopleViewModel()
@EnvironmentObject var profileviewModel: ProfileViewModel
private let items = [GridItem(), GridItem(), GridItem()]
var body: some View {
NavigationView {
VStack(spacing: 0) {
PeopleTopView()
.padding(.top, 45)
PeopleSearchBarView(text: $peoplesViewModel.searchText)
.padding()
ScrollView(.vertical, showsIndicators: false) {
NavigationLink {
ScrollView(.vertical, showsIndicators: false) {
ForEach(self.peoplesViewModel.users) { susers in
VStack {
ProfileInfoView(user: susers)
}
}
}
} label: {
LazyVGrid(columns: items, spacing: 2) {
ForEach(peoplesViewModel.searchableUsers) { peep in
PeepsGridView(userInfo: peep)
}
}
}
} //End ScrollView
}
.navigationBarTitle("")
.navigationBarHidden(true)
.ignoresSafeArea(.all, edges: .top)
} //End NavigationView
}
}
I am getting my users from Firebase so i will include the 2 view models i linked:
import Foundation
class PeopleViewModel: 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
}
}
}
This is the second view model:
import Foundation
class ProfileViewModel: ObservableObject {
@Published var feedtry = [FeedTry]()
@Published var likedTry = [FeedTry]()
private let service = UploadTryService()
private let userService = UserService()
var user: User
init (user: User) {
self.user = user
self.fetchUserFeedTry()
self.fetchLikedTry()
}
var actionButtonTitle: String {
return user.isCurrentUser ? "Edit Profile" : "Follow"
}
func feedtrys(forFilter filter: ProfileFilterViewModel) -> [FeedTry] {
switch filter {
case .music:
return feedtry
case .pictures:
return feedtry
case .videos:
return likedTry
}
}
func fetchUserFeedTry() {
guard let uid = user.id else { return }
service.fetchTry(forUid: uid) { feedtrys in
self.feedtry = feedtrys
for i in 0 ..< feedtrys.count {
self.feedtry[i].user = self.user
}
}
}
func fetchLikedTry() {
guard let uid = user.id else { return }
service.fetchLikedTry(forUid: uid) { feedtry in
self.likedTry = feedtry
for i in 0 ..< feedtry.count {
let uid = feedtry[i].uid
self.userService.fetchUser(withUid: uid) { user in
self.likedTry[i].user = user
}
}
}
}
}
And lastly this is the code i have above the body of my profile view:
import SwiftUI
import SDWebImageSwiftUI
struct ProfileView: View {
@ObservedObject var profileviewModel: ProfileViewModel
@Namespace var animation
init(user: User) {
self.profileviewModel = ProfileViewModel(user: user)
}
}
CodePudding user response:
You can't have one NavigationLink
that has all possibilities inside of it. Instead, you create all of your possibilities and then put a NavigationLink
around each possibility. The other issue with your code is you are using two different sets of data, one as the data model for the NavigationLink
, and the other as the data model for the label. These have to be the same, or else things are hopelessly confused. Further, if you do not always have an identical amount of susers
and peep
, you will have a crash when one runs out before the other. Since you wanted to navigate using susers
, I used that variable in the code below:
ScrollView(.vertical, showsIndicators: false) {
LazyVGrid(columns: items, spacing: 2) {
ForEach(self.peoplesViewModel.users) { susers in
NavigationLink {
ProfileInfoView(user: susers)
} label: {
PeepsGridView(userInfo: users)
}
}
}
} //End ScrollView