getting decently far in handling the data for friends and all

This commit is contained in:
talksik
2021-12-25 02:29:17 -08:00
parent fb56c79fe8
commit 225048152d
4 changed files with 76 additions and 86 deletions
+64 -74
View File
@@ -37,6 +37,8 @@ final class AuthSessionStore: ObservableObject, SessionStore {
var userFriendsDict: [String: UserFriends] = [:] // all active and inactive relationships
// transformed data for the views
@Published var friendsArr: [String] = []
@Published var inboxUsersArr: [String] = []
@Published var relevantUsersDict: [String: User] = [:] // all cached/snapshotted users from db for app use
@Published var relevantMessagesByUserDict: [String: [Message]] = [:] // note, this is all messages related to me
@@ -217,7 +219,7 @@ extension AuthSessionStore {
}
// MARK: keeping the @Published user object updated
// TODO: THIS WON"T UPDATE VIEW since user is a reference type...can manually publish...research and learn more
// TODO: THIS WON'T UPDATE VIEW since user is a reference type...can manually publish...research and learn more
self.firestoreService.getUserRealtime(userId: currUserId!) {[weak self] realtimeUpdatedUser in
if realtimeUpdatedUser != nil {
print("up to date user: \(realtimeUpdatedUser)")
@@ -228,24 +230,18 @@ extension AuthSessionStore {
// MARK: keeping the friends list updated
// TODO: break into firestoreService metadata of each change...later tho since this listener will barely get changes
// different actions on additions, modifications, and removals
// parse through the new result set
// if already exists in dict, then make sure not to delete the associated list
// order: when the relationship was created...also easy for user
// limit: for my protection of db costs lol
// TODO: use the indexes I created
let friendsListener = db.collection("user_friends").whereField("userId", isEqualTo: currUserId).limit(to: 100)
.addSnapshotListener { querySnapshot, error in
print("friends listener activated")
guard let documents = querySnapshot?.documents else {
print("Error fetching user's friends: \(error!)")
return
}
// resetting array to reset friends
self.relevantUsersDict.removeAll()
self.userFriendsDict.removeAll()
self.friendsArr.removeAll() // updating to keep the friends in order
for document in querySnapshot!.documents {
let userFriend:UserFriends? = try? document.data(as: UserFriends.self)
@@ -265,6 +261,18 @@ extension AuthSessionStore {
if returnedUser != nil {
self.relevantUsersDict[userFriend!.friendId] = returnedUser!
// making sure that I clear the inbox if this user came from the inbox...regardless of
// whether I accepted or rejected them
if self.inboxUsersArr.contains(userFriend!.friendId) {
self.inboxUsersArr = self.inboxUsersArr.filter {inboxUserId in
return inboxUserId != userFriend!.friendId
}
}
if userFriend!.isActive {
self.friendsArr.append(userFriend!.friendId)
}
self.objectWillChange.send()
print("added this user to the array of users for user's circle\(returnedUser?.nickname)")
@@ -276,28 +284,51 @@ extension AuthSessionStore {
}
}
}
// TODO: optimize later with the conditionals
// guard let snapshot = querySnapshot else {
// print("Error fetching user's friends: \(error!)")
// return
// }
// snapshot.documentChanges.forEach { diff in
//
// if (diff.type == .added) {
// print("New friend in circle: \(diff.document.data())")
// }
// if (diff.type == .modified) {
// // maybe it was deactivated or activated
// print("Modified relationship: \(diff.document.data())")
// }
// if (diff.type == .removed) {
// print("Removed city: \(diff.document.data())")
// }
// }
}
// listener for people who have me as an active friend might make inbox easier
// where friendId = me, isActive = true...this way it's a published property that can update the ui
// as inbox users is only being called on load
let inboxUsersListener = db.collection("user_friends").whereField("friendId", isEqualTo: currUserId).whereField("isActive", isEqualTo: true)
.addSnapshotListener { querySnapshot, error in
print("inbox users listener")
guard let documents = querySnapshot?.documents else {
print("Error fetching friends who have me as a friend: \(error!)")
return
}
self.inboxUsersArr.removeAll()
for document in querySnapshot!.documents {
let userFriend:UserFriends? = try? document.data(as: UserFriends.self)
if userFriend == nil {
continue
}
// if this user is not already a friend, active or inactive/rejected, then get their user data and add to inbox
if self.userFriendsDict.keys.contains(userFriend!.userId) {
print("already have this user in my circle or I rejected them \(userFriend?.friendId)")
continue
}
else {
self.firestoreService.getUser(userId: userFriend!.userId) {[weak self] returnedUser in
if returnedUser == nil {
print("couldn't get new user info")
return
}
print("new user for inbox fetched \(returnedUser!.nickname)")
DispatchQueue.main.async {
// add data to our app cache of users for their info down the road
self?.relevantUsersDict[userFriend!.userId] = returnedUser!
self?.inboxUsersArr.append(userFriend!.userId)
}
}
}
}
}
// MARK: listener for messages
@@ -309,6 +340,8 @@ extension AuthSessionStore {
// SOLUTION: composite with array
let messagesListener = db.collection("messages").whereField("senderIdReceiverIdComposite", arrayContains: currUserId).order(by: "sentTimestamp", descending: true).limit(to: 100)
.addSnapshotListener { querySnapshot, error in
print("messages listener activated")
guard let documents = querySnapshot?.documents else {
print("error in fetching messages: \(error!)")
return
@@ -343,22 +376,6 @@ extension AuthSessionStore {
} else {
self.relevantMessagesByUserDict[currMessage!.senderId]?.append(currMessage!)
}
// need to get and add this user to inbox if they are not a friend, active or inactive
// self.updateInboxUsers(currMessage!.senderId)
// might be an inbox message from someone completely new, but also can be a concurrency thing, where we haven't completely fetched all friends, active or inactive with the previous listener
// no worries though as we keep everything update to date in the view
if !self.relevantUsersDict.keys.contains(currMessage!.senderId) {
self.firestoreService.getUser(userId: currMessage!.senderId) {[weak self] returnedUser in
if returnedUser == nil {
print("couldn't get new user info")
return
}
print("new user for inbox fetched")
self?.relevantUsersDict[currMessage!.senderId] = returnedUser!
}
}
}
}
@@ -373,10 +390,6 @@ extension AuthSessionStore {
}
}
// listener for people who have me as an active friend might make inbox easier
// where friendId = me, isActive = true...this way it's a published property that can update the ui
// as inbox users is only being called on load
self.listenersActive = true
// adding listeners to be able to deinit later
@@ -384,6 +397,7 @@ extension AuthSessionStore {
// self.dataListeners.append(currUserListener)
self.dataListeners.append(messagesListener)
self.dataListeners.append(friendsListener)
self.dataListeners.append(inboxUsersListener)
}
@@ -397,27 +411,3 @@ extension AuthSessionStore {
self.listenersActive = false
}
}
// transforming data to make it more valuable
extension AuthSessionStore {
func getActiveFriendIds() -> [String] {
// TODO: order friends by user friend creation date as dictionaries don't have any inherent order
// they order randomly through hash value creation
var activeFriendIds: [String] = []
for (friendId, userFriend) in self.userFriendsDict {
if userFriend.isActive {
activeFriendIds.append(friendId)
}
}
return activeFriendIds
}
func getInboxUsersIds() -> [String] {
return self.relevantUsersDict.keys.filter {userId in
return !self.userFriendsDict.keys.contains(userId)
}
}
}
@@ -21,7 +21,7 @@ struct FindFriendsView: View {
// main content
NavigationView {
VStack {
Text("You must have someone in your phone contacts to add them. Remember: \(self.authSessionStore.getActiveFriendIds().count)/10 spots filled in your circle. 🥬")
Text("You must have someone in your phone contacts to add them. Remember: \(self.authSessionStore.friendsArr.count)/10 spots filled in your circle. 🥬")
.font(.subheadline)
.foregroundColor(Color.gray)
.padding(.horizontal)
@@ -58,13 +58,11 @@ struct FindFriendsView: View {
let keys = (Array(self.contactsVM.contacts.keys) as [String]).sorted()
// checking if currcontact is already a friend
let activeFriendIds = self.authSessionStore.getActiveFriendIds()
let newPotentialFriends = keys.filter {contactSortProp in
if let friend = self.contactsVM.contacts[contactSortProp]?.user { // seeing if this contact is an existing user
// if this is already an ACTIVE friend -> don't show
// we want to show inactive friends
if activeFriendIds.contains(friend.id!) {
if self.authSessionStore.friendsArr.contains(friend.id!) {
return false
}
@@ -55,8 +55,8 @@ struct CircleGridView: View {
// based on most close friends to least
// MARK: data entry point
let activeFriends = self.authSessionStore.getActiveFriendIds()
let inboxUsers = self.authSessionStore.getInboxUsersIds()
let activeFriends = self.authSessionStore.friendsArr
let inboxUsers = self.authSessionStore.inboxUsersArr
ScrollViewReader {scrollReaderValue in
ScrollView([.horizontal, .vertical], showsIndicators: false) {
@@ -152,15 +152,17 @@ struct CircleGridView: View {
// inbox users
ForEach(0..<inboxUsers.count, id: \.self) {inboxValue in
let inboxUserId = inboxUsers[inboxValue]
let adjustedValue = inboxValue + self.authSessionStore.getActiveFriendIds().count // IMPORTANT: accounting for the active friends iterations
let adjustedValue = inboxValue + activeFriends.count // IMPORTANT: accounting for the active friends iterations
GeometryReader {gridProxy in
let scale = getScale(proxy: gridProxy, itemNumber: adjustedValue, userId: inboxUserId) * 0.75 // don't want inbox to match size of active
ZStack(alignment: .topTrailing) {
Image(systemName: "arrow.down.left.circle.fill")
.foregroundColor(NirvanaColor.dimTeal)
.font(.title)
Text("\(activeFriends.count)")
Circle()
.foregroundColor(NirvanaColor.dimTeal.opacity(0.3)) // different color for a selected user
.blur(radius: 5)
@@ -187,7 +189,7 @@ struct CircleGridView: View {
let inboxFriendNumber = self.authSessionStore.relevantUsersDict[inboxUserId]?.phoneNumber
self.alertText = "🌴Add to your circle?"
self.alertSubtext = "\(inboxFriendName ?? "") started a convo with you... \n \(inboxFriendNumber!) \n Remember: you have \(10 - activeFriends.count) spots left!"
self.alertSubtext = "\(inboxFriendName ?? "") started a convo with you... \n \(inboxFriendNumber ?? "") \n Remember: you have \(10 - activeFriends.count) spots left!"
self.alertActive.toggle()
}
.animation(Animation.spring())
@@ -212,7 +214,7 @@ struct CircleGridView: View {
}
// stale state for adding a contact
let staleAdjustedValue = self.authSessionStore.getActiveFriendIds().count + self.authSessionStore.getInboxUsersIds().count
let staleAdjustedValue = activeFriends.count + inboxUsers.count
GeometryReader {gridProxy in
let scale = getScale(proxy: gridProxy, itemNumber: staleAdjustedValue, userId: nil) * 0.75 // adjusting size as stale states should be the smallest
Button {
@@ -56,7 +56,7 @@ struct InnerCircleView: View {
}
.padding()
}
else if self.authSessionStore.getActiveFriendIds().count == 0 && self.authSessionStore.getInboxUsersIds().count == 0 {
else if self.authSessionStore.friendsArr.count == 0 && self.authSessionStore.inboxUsersArr.count == 0 {
VStack(alignment: .center) {
Image("undraw_fall_is_coming_yl-0-x")
.renderingMode(.original)
@@ -102,7 +102,7 @@ struct InnerCircleView: View {
// helper for new users
// TODO: make it back to 1 instead of 10...testing
if self.authSessionStore.getActiveFriendIds().count == 1 && self.selectedFriendIndex == nil { // don't show if bottom metadata showing
if self.authSessionStore.friendsArr.count == 1 && self.selectedFriendIndex == nil { // don't show if bottom metadata showing
ZStack(alignment: .bottomTrailing) {
Color.clear