nicer ui to play things and moving things all to the view model for listening to messages and much cleaner
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
8909199E278155920025F4BB /* UserStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8909199D278155920025F4BB /* UserStatusView.swift */; };
|
8909199E278155920025F4BB /* UserStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8909199D278155920025F4BB /* UserStatusView.swift */; };
|
||||||
890919A42781845D0025F4BB /* AlertToast in Frameworks */ = {isa = PBXBuildFile; productRef = 890919A32781845D0025F4BB /* AlertToast */; };
|
890919A42781845D0025F4BB /* AlertToast in Frameworks */ = {isa = PBXBuildFile; productRef = 890919A32781845D0025F4BB /* AlertToast */; };
|
||||||
890919A7278299590025F4BB /* RuleBook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890919A6278299590025F4BB /* RuleBook.swift */; };
|
890919A7278299590025F4BB /* RuleBook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890919A6278299590025F4BB /* RuleBook.swift */; };
|
||||||
|
890919AB2782DC760025F4BB /* ProgressBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890919AA2782DC760025F4BB /* ProgressBarView.swift */; };
|
||||||
890C245D277BF628009B4A30 /* AgoraRtcKit in Frameworks */ = {isa = PBXBuildFile; productRef = 890C245C277BF628009B4A30 /* AgoraRtcKit */; };
|
890C245D277BF628009B4A30 /* AgoraRtcKit in Frameworks */ = {isa = PBXBuildFile; productRef = 890C245C277BF628009B4A30 /* AgoraRtcKit */; };
|
||||||
890C2460277BF896009B4A30 /* AgoraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890C245F277BF896009B4A30 /* AgoraViewController.swift */; };
|
890C2460277BF896009B4A30 /* AgoraViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890C245F277BF896009B4A30 /* AgoraViewController.swift */; };
|
||||||
890C2462277BF935009B4A30 /* CallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890C2461277BF935009B4A30 /* CallView.swift */; };
|
890C2462277BF935009B4A30 /* CallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890C2461277BF935009B4A30 /* CallView.swift */; };
|
||||||
@@ -107,6 +108,7 @@
|
|||||||
8909199B277EFDF30025F4BB /* joinSound.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = joinSound.mp3; sourceTree = "<group>"; };
|
8909199B277EFDF30025F4BB /* joinSound.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = joinSound.mp3; sourceTree = "<group>"; };
|
||||||
8909199D278155920025F4BB /* UserStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserStatusView.swift; sourceTree = "<group>"; };
|
8909199D278155920025F4BB /* UserStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserStatusView.swift; sourceTree = "<group>"; };
|
||||||
890919A6278299590025F4BB /* RuleBook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleBook.swift; sourceTree = "<group>"; };
|
890919A6278299590025F4BB /* RuleBook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleBook.swift; sourceTree = "<group>"; };
|
||||||
|
890919AA2782DC760025F4BB /* ProgressBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarView.swift; sourceTree = "<group>"; };
|
||||||
890C245F277BF896009B4A30 /* AgoraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgoraViewController.swift; sourceTree = "<group>"; };
|
890C245F277BF896009B4A30 /* AgoraViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgoraViewController.swift; sourceTree = "<group>"; };
|
||||||
890C2461277BF935009B4A30 /* CallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallView.swift; sourceTree = "<group>"; };
|
890C2461277BF935009B4A30 /* CallView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallView.swift; sourceTree = "<group>"; };
|
||||||
890C2463277BFA97009B4A30 /* AgroRep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgroRep.swift; sourceTree = "<group>"; };
|
890C2463277BFA97009B4A30 /* AgroRep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgroRep.swift; sourceTree = "<group>"; };
|
||||||
@@ -332,6 +334,7 @@
|
|||||||
89288ECA27675B9F00E962C4 /* OnboardingTemplateView.swift */,
|
89288ECA27675B9F00E962C4 /* OnboardingTemplateView.swift */,
|
||||||
89BCABEC276D2B05009E9B10 /* WavesGlassBackgroundView.swift */,
|
89BCABEC276D2B05009E9B10 /* WavesGlassBackgroundView.swift */,
|
||||||
8909199D278155920025F4BB /* UserStatusView.swift */,
|
8909199D278155920025F4BB /* UserStatusView.swift */,
|
||||||
|
890919AA2782DC760025F4BB /* ProgressBarView.swift */,
|
||||||
);
|
);
|
||||||
path = Templates;
|
path = Templates;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -674,6 +677,7 @@
|
|||||||
89F05BA6276ACD830002E9C7 /* ContactsPickerView.swift in Sources */,
|
89F05BA6276ACD830002E9C7 /* ContactsPickerView.swift in Sources */,
|
||||||
8904DEC8277055E90071E6CA /* OnboardingOneView.swift in Sources */,
|
8904DEC8277055E90071E6CA /* OnboardingOneView.swift in Sources */,
|
||||||
896CE7022770892F00DB474E /* CircleGridView.swift in Sources */,
|
896CE7022770892F00DB474E /* CircleGridView.swift in Sources */,
|
||||||
|
890919AB2782DC760025F4BB /* ProgressBarView.swift in Sources */,
|
||||||
89091995277DD9F80025F4BB /* ConvoFooterView.swift in Sources */,
|
89091995277DD9F80025F4BB /* ConvoFooterView.swift in Sources */,
|
||||||
8909199E278155920025F4BB /* UserStatusView.swift in Sources */,
|
8909199E278155920025F4BB /* UserStatusView.swift in Sources */,
|
||||||
89BDCDEA27697F9C00577829 /* UserMenu.swift in Sources */,
|
89BDCDEA27697F9C00577829 /* UserMenu.swift in Sources */,
|
||||||
|
|||||||
@@ -36,7 +36,12 @@ struct CircleFooterView: View {
|
|||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
.overlay(alignment: .topTrailing) {
|
.overlay(alignment: .topTrailing) {
|
||||||
// user status
|
// user status
|
||||||
UserStatusView(status: self.selectedFriend!.userStatus, size: 10)
|
ZStack(alignment: .topTrailing) {
|
||||||
|
ProgressBarView(progress: self.innerCircleVM.messagesListeningProgress, color: self.myTurn ?? false ? Color.orange : NirvanaColor.dimTeal)
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
|
||||||
|
UserStatusView(status: self.selectedFriend!.userStatus, size: 10)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.padding(5)
|
.padding(5)
|
||||||
.contextMenu {
|
.contextMenu {
|
||||||
@@ -79,13 +84,12 @@ struct CircleFooterView: View {
|
|||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
.foregroundColor(.gray)
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: 60) // 60 is the height of the footer control big circle
|
.frame(maxWidth: .infinity, maxHeight: 60) // 60 is the height of the footer control big circle
|
||||||
.background(Color.white.opacity(0.5))
|
.background(Color.white.opacity(0.5))
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ struct CircleGridView: View {
|
|||||||
@EnvironmentObject var navigationStack: NavigationStack
|
@EnvironmentObject var navigationStack: NavigationStack
|
||||||
@EnvironmentObject var convoVM: ConvoViewModel
|
@EnvironmentObject var convoVM: ConvoViewModel
|
||||||
|
|
||||||
@State var queuePlayer = AVQueuePlayer()
|
|
||||||
@State var timeObserverToken: Any?
|
|
||||||
|
|
||||||
@GestureState var dragState = DragState.inactive
|
@GestureState var dragState = DragState.inactive
|
||||||
|
|
||||||
let universalSize = UIScreen.main.bounds
|
let universalSize = UIScreen.main.bounds
|
||||||
@@ -158,6 +155,11 @@ struct CircleGridView: View {
|
|||||||
.blur(radius: 8)
|
.blur(radius: 8)
|
||||||
.cornerRadius(100)
|
.cornerRadius(100)
|
||||||
|
|
||||||
|
if self.haveNewMessageFromFriend(friendDbId: friendId) {
|
||||||
|
ProgressBarView(progress: self.selectedFriendIndex == friendId ? self.innerCircleVM.messagesListeningProgress : Float(1), color: Color.orange)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// user status
|
// user status
|
||||||
UserStatusView(status: self.authSessionStore.relevantUsersDict[friendId]?.userStatus, size: 20, padding: 5)
|
UserStatusView(status: self.authSessionStore.relevantUsersDict[friendId]?.userStatus, size: 20, padding: 5)
|
||||||
|
|
||||||
@@ -191,7 +193,7 @@ struct CircleGridView: View {
|
|||||||
self.activateHaptics()
|
self.activateHaptics()
|
||||||
|
|
||||||
// stop any player still playing of a message
|
// stop any player still playing of a message
|
||||||
self.queuePlayer.removeAllItems()
|
self.innerCircleVM.stopPlayingAnyAudio()
|
||||||
|
|
||||||
// if friend and I are online, and I am not in a convo, start convo immediately with them
|
// if friend and I are online, and I am not in a convo, start convo immediately with them
|
||||||
if self.authSessionStore.relevantUsersDict[friendId]?.userStatus == .online
|
if self.authSessionStore.relevantUsersDict[friendId]?.userStatus == .online
|
||||||
@@ -523,9 +525,9 @@ extension CircleGridView {
|
|||||||
self.convoVM.toast = .alreadyInCall
|
self.convoVM.toast = .alreadyInCall
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// clearing the player to make room for this friend's convo or to deselect this user
|
// when deselecting, want to stop playing
|
||||||
self.queuePlayer.removeAllItems()
|
self.innerCircleVM.stopPlayingAnyAudio()
|
||||||
|
|
||||||
// if user had previously selected user, put nil as a toggle
|
// if user had previously selected user, put nil as a toggle
|
||||||
if self.selectedFriendIndex == friendId {
|
if self.selectedFriendIndex == friendId {
|
||||||
@@ -535,17 +537,13 @@ extension CircleGridView {
|
|||||||
self.selectedFriendIndex = friendId
|
self.selectedFriendIndex = friendId
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: OPTIMIZATION...buffer and load all AVAssets to create AVPlayerItems before a tap happens...but this can also cause load in background if user is not playing a message right now...this isn't an optimization of the data/firestore but rather the player
|
|
||||||
|
|
||||||
// I want to play the last x messages if I was the receiver...the array is sorted from backend so that the
|
// I want to play the last x messages if I was the receiver...the array is sorted from backend so that the
|
||||||
// most recent comes first
|
// most recent comes first
|
||||||
// ["sarth": [ME, HIM...]] -> play nothing
|
// ["sarth": [ME, HIM...]] -> play nothing
|
||||||
// ["sarth": [HIM, HIM, me, him...]] -> play his two messages
|
// ["sarth": [HIM, HIM, me, him...]] -> play his two messages
|
||||||
|
|
||||||
// traverse through reversed list of messages and add to audio player queue
|
// traverse through reversed list of messages and add to audio player queue
|
||||||
// TODO: protect against force unwraps
|
var audioUrls: [URL] = []
|
||||||
var AVPlayerItems: [AVPlayerItem] = []
|
|
||||||
var AVAssets: [AVAsset] = []
|
|
||||||
let messagesRelatedToFriend = self.authSessionStore.relevantMessagesByUserDict[friendId] ?? []
|
let messagesRelatedToFriend = self.authSessionStore.relevantMessagesByUserDict[friendId] ?? []
|
||||||
|
|
||||||
if messagesRelatedToFriend.count == 0 {
|
if messagesRelatedToFriend.count == 0 {
|
||||||
@@ -553,7 +551,6 @@ extension CircleGridView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for message in messagesRelatedToFriend {
|
for message in messagesRelatedToFriend {
|
||||||
print("message: the sender is \(message.senderId) and senttime: \(message.sentTimestamp)")
|
|
||||||
// if it's starting to get to my messages then don't play
|
// if it's starting to get to my messages then don't play
|
||||||
if message.senderId == self.authSessionStore.user?.id {
|
if message.senderId == self.authSessionStore.user?.id {
|
||||||
break
|
break
|
||||||
@@ -561,88 +558,12 @@ extension CircleGridView {
|
|||||||
|
|
||||||
// only add to queue if we can convert the database url to a valid url here
|
// only add to queue if we can convert the database url to a valid url here
|
||||||
if let audioUrl = URL(string: message.audioDataUrl) {
|
if let audioUrl = URL(string: message.audioDataUrl) {
|
||||||
let playerMessage: AVPlayerItem = AVPlayerItem(url: audioUrl)
|
audioUrls.append(audioUrl)
|
||||||
let playerAsset: AVAsset = AVAsset(url: audioUrl)
|
|
||||||
AVAssets.append(playerAsset)
|
|
||||||
AVPlayerItems.append(playerMessage)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// start playing if there are messages to listen to
|
// plays everything from vm
|
||||||
if AVPlayerItems.count > 0 {
|
self.innerCircleVM.playAssets(audioUrls: audioUrls)
|
||||||
print("have \(AVPlayerItems.count) messages to play")
|
|
||||||
|
|
||||||
// reverse the items because we want to listen to the most recent messages in order
|
|
||||||
AVPlayerItems = AVPlayerItems.reversed()
|
|
||||||
queuePlayer = AVQueuePlayer(items: AVPlayerItems)
|
|
||||||
|
|
||||||
// TODO: make sure these options are viable for different scenarios
|
|
||||||
queuePlayer.automaticallyWaitsToMinimizeStalling = false
|
|
||||||
queuePlayer.playImmediately(atRate: 1)
|
|
||||||
// queuePlayer.play()
|
|
||||||
|
|
||||||
print("player queued up items!!!")
|
|
||||||
|
|
||||||
// notify every half second
|
|
||||||
// let timeScale = CMTimeScale(NSEC_PER_SEC)
|
|
||||||
// let time = CMTime(seconds: 0.5, preferredTimescale: timeScale)
|
|
||||||
|
|
||||||
// timeObserverToken = queuePlayer.addPeriodicTimeObserver(forInterval: time, queue: .main) {time in
|
|
||||||
// // update player transport UI
|
|
||||||
// print("periodic time observer: \(time)")
|
|
||||||
// // if the current playeritem is the latest one:
|
|
||||||
// // 1. deselect this user
|
|
||||||
// // 2. update databse that I listened to this
|
|
||||||
// if queuePlayer.currentItem == AVPlayerItems.last {
|
|
||||||
// // hide the footer now...ehhh don't need to
|
|
||||||
//// DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
||||||
//// self.selectedFriendIndex = nil
|
|
||||||
//// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: right now not updating all of that
|
|
||||||
// update the listencount and firstlistentimestamp of those messages in firestore
|
|
||||||
// this should update ui to show that there is no message to show
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func addBoundaryTimeObserver(playerAssets: [AVAsset]) {
|
|
||||||
var totalDuration = CMTime.zero
|
|
||||||
for item in playerAssets {
|
|
||||||
print(item.duration)
|
|
||||||
totalDuration = CMTimeAdd(item.duration, totalDuration)
|
|
||||||
}
|
|
||||||
print(totalDuration)
|
|
||||||
|
|
||||||
// Divide the total duration into quarters.
|
|
||||||
let interval = CMTimeMultiplyByFloat64(totalDuration, multiplier: 0.95)
|
|
||||||
var currentTime = CMTime.zero
|
|
||||||
var times = [NSValue]()
|
|
||||||
|
|
||||||
// Calculate boundary times
|
|
||||||
while currentTime < totalDuration {
|
|
||||||
currentTime = currentTime + interval
|
|
||||||
times.append(NSValue(time:currentTime))
|
|
||||||
}
|
|
||||||
|
|
||||||
print(times)
|
|
||||||
|
|
||||||
timeObserverToken = queuePlayer.addBoundaryTimeObserver(forTimes: times,
|
|
||||||
queue: DispatchQueue.main) {
|
|
||||||
// Update UI
|
|
||||||
print("activated time boundary")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeBoundaryTimeObserver() {
|
|
||||||
if let timeObserverToken = timeObserverToken {
|
|
||||||
self.queuePlayer.removeTimeObserver(timeObserverToken)
|
|
||||||
self.timeObserverToken = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DragState {
|
enum DragState {
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ struct CircleNavigationView: View {
|
|||||||
.animation(.spring())
|
.animation(.spring())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import AVKit
|
||||||
import AlertToast
|
import AlertToast
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
class InnerCircleViewModel: ObservableObject {
|
|
||||||
|
class InnerCircleViewModel: NSObject, ObservableObject {
|
||||||
@Published var toast: Toast? {
|
@Published var toast: Toast? {
|
||||||
didSet {
|
didSet {
|
||||||
self.showToast = true
|
self.showToast = true
|
||||||
@@ -67,13 +69,14 @@ class InnerCircleViewModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var audioRecorder : AVAudioRecorder!
|
var audioRecorder : AVAudioRecorder!
|
||||||
var audioPlayer : AVAudioPlayer!
|
var queuePlayer = AVQueuePlayer()
|
||||||
|
|
||||||
@Published var isRecording : Bool = false
|
@Published var isRecording : Bool = false
|
||||||
|
|
||||||
|
@Published var messagesListeningProgress: Float = 0.0
|
||||||
|
|
||||||
let audioSession = AVAudioSession.sharedInstance()
|
let audioSession = AVAudioSession.sharedInstance()
|
||||||
|
|
||||||
private var audioLocalUrl: URL?
|
private var audioLocalUrl: URL?
|
||||||
@@ -83,7 +86,9 @@ class InnerCircleViewModel: ObservableObject {
|
|||||||
private let pushNotificationService = PushNotificationService()
|
private let pushNotificationService = PushNotificationService()
|
||||||
|
|
||||||
|
|
||||||
init() {
|
override init() {
|
||||||
|
super.init()
|
||||||
|
|
||||||
// separate set up for listening vs recording
|
// separate set up for listening vs recording
|
||||||
do {
|
do {
|
||||||
try audioSession.setCategory(.playAndRecord, mode: .default, options: [.duckOthers, .allowBluetooth, .allowBluetoothA2DP])
|
try audioSession.setCategory(.playAndRecord, mode: .default, options: [.duckOthers, .allowBluetooth, .allowBluetoothA2DP])
|
||||||
@@ -238,3 +243,133 @@ extension InnerCircleViewModel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// everything to do with listening to messages
|
||||||
|
extension InnerCircleViewModel {
|
||||||
|
func stopPlayingAnyAudio() {
|
||||||
|
self.queuePlayer.removeAllItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: print statements slowing it down?
|
||||||
|
func playAssets(audioUrls: [URL]) {
|
||||||
|
// clearing the player to make room for this friend's convo or to deselect this user
|
||||||
|
self.stopPlayingAnyAudio()
|
||||||
|
|
||||||
|
var totalMessagesDurationSeconds = CMTime.zero
|
||||||
|
var AVPlayerItems: [AVPlayerItem] = []
|
||||||
|
for url in audioUrls {
|
||||||
|
let asset = AVAsset(url: url)
|
||||||
|
let playerItem = AVPlayerItem(asset: asset)
|
||||||
|
|
||||||
|
totalMessagesDurationSeconds = CMTimeAdd(totalMessagesDurationSeconds, asset.duration)
|
||||||
|
|
||||||
|
// 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 AVPlayerItems.count <= 0 {
|
||||||
|
print("no messages to play...send a message to user")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// start playing if there are messages to listen to
|
||||||
|
print("have \(AVPlayerItems.count) messages and \(totalMessagesDurationSeconds) seconds to play")
|
||||||
|
|
||||||
|
// reverse the items because we want to listen to the most recent messages in order
|
||||||
|
AVPlayerItems = AVPlayerItems.reversed()
|
||||||
|
|
||||||
|
// TODO: make sure these options are viable for different scenarios
|
||||||
|
self.queuePlayer = AVQueuePlayer(items: AVPlayerItems)
|
||||||
|
self.queuePlayer.automaticallyWaitsToMinimizeStalling = false
|
||||||
|
self.queuePlayer.playImmediately(atRate: 1)
|
||||||
|
// queuePlayer.play()
|
||||||
|
|
||||||
|
print("player queued up items!!!")
|
||||||
|
|
||||||
|
self.addBoundaryTimeObserver(totalDuration: totalMessagesDurationSeconds)
|
||||||
|
|
||||||
|
// TODO: right now not updating all of that
|
||||||
|
// update the listencount and firstlistentimestamp of those messages in firestore
|
||||||
|
// this should update ui to show that there is no message to show
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func addBoundaryTimeObserver(totalDuration: CMTime) {
|
||||||
|
var multiplier: Float64 = 0.05
|
||||||
|
|
||||||
|
// reset progress
|
||||||
|
self.messagesListeningProgress = Float(multiplier * 2)
|
||||||
|
|
||||||
|
var times = [NSValue]()
|
||||||
|
// Set initial time to zero
|
||||||
|
var currentTime = CMTime.zero
|
||||||
|
// Divide the asset's duration into quarters.
|
||||||
|
let interval = CMTimeMultiplyByFloat64(totalDuration, multiplier: multiplier)
|
||||||
|
|
||||||
|
// Build boundary times based on multiplier
|
||||||
|
while currentTime <= totalDuration {
|
||||||
|
currentTime = currentTime + interval
|
||||||
|
times.append(NSValue(time: currentTime))
|
||||||
|
}
|
||||||
|
// this last one to make sure we get a full loop
|
||||||
|
times.append(NSValue(time: totalDuration))
|
||||||
|
|
||||||
|
// Add time observer. Observe boundary time changes on the main queue.
|
||||||
|
// TODO: not hitting the last one/100%
|
||||||
|
self.queuePlayer.addBoundaryTimeObserver(forTimes: times, queue: .main) { [weak self] in
|
||||||
|
// Update UI
|
||||||
|
self?.messagesListeningProgress += Float(multiplier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// func periodTimeObserver() {
|
||||||
|
|
||||||
|
// notify every half second
|
||||||
|
// let timeScale = CMTimeScale(NSEC_PER_SEC)
|
||||||
|
// let time = CMTime(seconds: 0.5, preferredTimescale: timeScale)
|
||||||
|
|
||||||
|
|
||||||
|
// have the total duration, let's say 100
|
||||||
|
|
||||||
|
// want to keep adding to our backend: seconds listened so far
|
||||||
|
|
||||||
|
// devide by the total duration seconds to get the progress
|
||||||
|
|
||||||
|
// var totalListened: Double = 0.0
|
||||||
|
// var lastValue: Double = 0.0
|
||||||
|
// queuePlayer.addPeriodicTimeObserver(forInterval: time, queue: .main) { [weak self] TOTime in
|
||||||
|
// // reset counter once we get to subsequent playeritems
|
||||||
|
// if TOTime.seconds < lastValue {
|
||||||
|
// totalListened += (TOTime.seconds - 0)
|
||||||
|
// } else {
|
||||||
|
// totalListened += (TOTime.seconds - lastValue)
|
||||||
|
// }
|
||||||
|
// print("\(TOTime.seconds)")
|
||||||
|
// print("total seconds listened so far \(totalListened)")
|
||||||
|
//
|
||||||
|
// self?.messagesListeningProgress = Float(totalListened / totalMessagesDurationSeconds)
|
||||||
|
//
|
||||||
|
// lastValue = TOTime.seconds
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func removeBoundaryTimeObserver() {
|
||||||
|
// if let timeObserverToken = timeObserverToken {
|
||||||
|
// self.queuePlayer.removeTimeObserver(timeObserverToken)
|
||||||
|
// self.timeObserverToken = nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension InnerCircleViewModel {
|
||||||
|
// @objc func playerDidFinishPlaying(sender: Notification) {
|
||||||
|
// // Your code here
|
||||||
|
// print("finished playing an item")
|
||||||
|
//
|
||||||
|
// self.numberofMessagesToPlay -= 1
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// ProgressBarView.swift
|
||||||
|
// nirvana-ios
|
||||||
|
//
|
||||||
|
// Created by Arjun Patel on 1/2/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ProgressBarView: View {
|
||||||
|
var progress: Float
|
||||||
|
var color: Color = Color.orange
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Circle()
|
||||||
|
.trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
|
||||||
|
.stroke(style: StrokeStyle(lineWidth: 2.0, lineCap: .round, lineJoin: .round))
|
||||||
|
.foregroundColor(color)
|
||||||
|
.rotationEffect(Angle(degrees: 270.0))
|
||||||
|
.animation(.linear)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//struct ProgressBarView_Previews: PreviewProvider {
|
||||||
|
// static var previews: some View {
|
||||||
|
// ProgressBarView()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
Reference in New Issue
Block a user