From b77ae21973b6ee498cb9fcc8378a6a3112b2bed8 Mon Sep 17 00:00:00 2001 From: talksik Date: Mon, 3 Jan 2022 18:24:00 -0800 Subject: [PATCH] getting it sort of working but have a freeze --- nirvana-ios/Services/AuthSessionStore.swift | 6 +- .../Views/InnerCircle/CircleGridView.swift | 13 +++- .../InnerCircle/InnerCircleViewModel.swift | 78 ++++++++++++++----- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/nirvana-ios/Services/AuthSessionStore.swift b/nirvana-ios/Services/AuthSessionStore.swift index 8a5b2ee..c6de9c3 100644 --- a/nirvana-ios/Services/AuthSessionStore.swift +++ b/nirvana-ios/Services/AuthSessionStore.swift @@ -33,7 +33,7 @@ final class AuthSessionStore: ObservableObject, SessionStore { @Published var sessionState: SessionState = SessionState.notCheckedYet // TODO: figure out which ones to publish - var messagesArr: [Message] = [] + @Published var messagesArr: [Message] = [] var userFriendsDict: [String: UserFriends] = [:] // all active and inactive relationships // transformed data for the views @@ -337,7 +337,7 @@ extension AuthSessionStore { // 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?.userId)") +// print("already have this user in my circle or I rejected them \(userFriend?.userId)") continue } else { @@ -383,7 +383,7 @@ extension AuthSessionStore { self.messagesArr = documents.compactMap { (queryDocumentSnapshot) -> Message? in do { let currMessage = try queryDocumentSnapshot.data(as: Message.self) - print("new message received! \(currMessage!.sentTimestamp)") +// print("new message received! \(currMessage!.sentTimestamp)") DispatchQueue.main.async { if currMessage != nil { // not really possible but just check diff --git a/nirvana-ios/Views/InnerCircle/CircleGridView.swift b/nirvana-ios/Views/InnerCircle/CircleGridView.swift index 2fd6761..845d72a 100644 --- a/nirvana-ios/Views/InnerCircle/CircleGridView.swift +++ b/nirvana-ios/Views/InnerCircle/CircleGridView.swift @@ -368,10 +368,15 @@ struct CircleGridView: View { } self.animateLiveConvos = true - }// univseral alert TODO: move to inner circle view and use this pattern for all view models -// .alert(item: self.$convoVM.error) {error in -// error.alert -// } + } + .onReceive(self.authSessionStore.$messagesArr) {_ in + // TODO: don't know if this fires if I am active and I receive a message but that's not something I am allowing right now with the continuous convo feature + + print("new messages found!!!! on receive going to cache all messages to load them faster for you!") + + // TODO: might be including messages of inbox users? overloading memory? + self.innerCircleVM.cacheIncomingMessages(friendMessagesDict: self.authSessionStore.relevantMessagesByUserDict) + } } // scrollview reader } diff --git a/nirvana-ios/Views/InnerCircle/InnerCircleViewModel.swift b/nirvana-ios/Views/InnerCircle/InnerCircleViewModel.swift index 7c75871..9f028ce 100644 --- a/nirvana-ios/Views/InnerCircle/InnerCircleViewModel.swift +++ b/nirvana-ios/Views/InnerCircle/InnerCircleViewModel.swift @@ -71,7 +71,9 @@ class InnerCircleViewModel: NSObject, ObservableObject { } var audioRecorder : AVAudioRecorder! + var queuePlayer = AVQueuePlayer() + private var cachedPlayerItemsDict: [String: Data] = [:] // url to player item @Published var isRecording : Bool = false @@ -255,15 +257,22 @@ extension InnerCircleViewModel { // clearing the player to make room for this friend's convo or to deselect this user self.stopPlayingAnyAudio() - var AVPlayerItems: [AVPlayerItem] = [] + // reset progress + self.messagesListeningProgress = Float(Self.multiplier * 2) + + var AVPlayerItems: [CachingPlayerItem] = [] for url in audioUrls { - let asset = AVAsset(url: url) - let playerItem = AVPlayerItem(asset: asset) - - // notification for when each playeritem is done playing -// NotificationCenter.default.addObserver(self, selector: #selector(self.playerDidFinishPlaying(sender:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem) - - AVPlayerItems.append(playerItem) + // if we have a player in the cache, then play it from there + if self.cachedPlayerItemsDict.keys.contains(url.absoluteString), let data = self.cachedPlayerItemsDict[url.absoluteString] { + // keep the cachedplayer item in tact as the player messes with those items + let cachedPlayerItem = CachingPlayerItem(data: data, mimeType: "audio/mp4", fileExtension: "m4a") + AVPlayerItems.append(cachedPlayerItem) + print("playing a message from cache") + } else { + let asset = AVAsset(url: url) + let playerItem = CachingPlayerItem(url: url) + AVPlayerItems.append(playerItem) + } } if AVPlayerItems.count <= 0 { @@ -271,6 +280,8 @@ extension InnerCircleViewModel { return } + print("current state of cached audio files: \(self.cachedPlayerItemsDict)") + // start playing if there are messages to listen to print("have \(AVPlayerItems.count) messages to play") @@ -284,9 +295,6 @@ extension InnerCircleViewModel { print("player queued up items!!!") - // reset progress - self.messagesListeningProgress = Float(Self.multiplier * 2) - DispatchQueue.global(qos: .background).async { self.addBoundaryTimeObserver(playerItems: AVPlayerItems) } @@ -357,14 +365,46 @@ extension InnerCircleViewModel { // self.timeObserverToken = nil // } // } + + func cacheIncomingMessages(friendMessagesDict: [String: [Message]]) { + // need way of making this get called whenever there are messages that come in but do all this in the background...onreceive of new messages, check if we already have it cached, and if not, then download + guard let userId = AuthSessionStore.getCurrentUserId() else {return} + DispatchQueue.global(qos: .background).async { + // get all relevant messages that the user may listen to + // don't want to cache all messages + for friendId in friendMessagesDict.keys { + let messagesRelatedToFriend = friendMessagesDict[friendId] ?? [] + + if messagesRelatedToFriend.count == 0 { + return + } + + for message in messagesRelatedToFriend { + // if it's starting to get to my messages then don't play + if message.senderId == userId { + break + } + + // only add to queue if we can convert the database url to a valid url here + if let audioUrl = URL(string: message.audioDataUrl) { // check if it's a valid url + if !self.cachedPlayerItemsDict.keys.contains(message.audioDataUrl) { + // save to play from mem later + let task = URLSession.shared.dataTask(with: audioUrl) {[weak self] (data, response, error) in + guard let data = data else { return } + print(data) + self?.cachedPlayerItemsDict[audioUrl.absoluteString] = data as? Data + } + + task.resume() + } + } + } + } + } + + // TODO: need way of deleting cache when we close app or something...can rile up the cost + } } -extension InnerCircleViewModel { -// @objc func playerDidFinishPlaying(sender: Notification) { -// // Your code here -// print("finished playing an item") -// -// self.numberofMessagesToPlay -= 1 -// } -} +