adding toasts like crazy

This commit is contained in:
talksik
2022-01-02 17:43:06 -08:00
parent ddb7380511
commit 57f8dd4dc9
6 changed files with 169 additions and 52 deletions
@@ -8,8 +8,45 @@
import Foundation
import Contacts
import SwiftUI
import AlertToast
class ContactsViewModel : ObservableObject {
@Published var toast: Toast? {
didSet {
self.showToast = true
}
}
@Published var showToast: Bool = false
enum Toast: Identifiable {
var id: Self { self }
case maxFriendsInCircle
case cannotFriendYourself
case addedFriend
case removedFriend
case fetchingContacts
case generalError
var view: AlertToast {
switch self {
case .fetchingContacts:
return AlertToast(displayMode: .hud, type: .systemImage("person.3.fill", NirvanaColor.dimTeal), title: "looking for friends")
case .removedFriend:
return AlertToast(displayMode: .hud, type: .complete(Color.green), title: "removed friend")
case .addedFriend:
return AlertToast(displayMode: .hud, type: .complete(Color.green), title: "added friend")
case .cannotFriendYourself:
return AlertToast(displayMode: .hud, type: .error(Color.orange), title: "silly! 🙉", subTitle: "you cannot friend yourself")
case .maxFriendsInCircle:
return AlertToast(displayMode: .hud, type: .systemImage("person.crop.circle.badge.exclamationmark.fill", Color.orange), title: "circle full!", subTitle: "tap on an existing friend and hold down on their icon in the bottom left to remove them to make space")
default:
return AlertToast(displayMode: .hud, type: .error(Color.orange), title: "Something went wrong ‼️")
}
}
}
@Published var showPermissionAlert = false
@Published var contacts: [String: ContactsViewModelContact] = [:]
@@ -48,6 +85,8 @@ class ContactsViewModel : ObservableObject {
fetchRequest.sortOrder = .userDefault
do {
self.toast = .fetchingContacts
try store.enumerateContacts(with: fetchRequest) {[weak self](contact, stop) in
// only checking if american number or not for now
var cnPhoneNumber = contact.phoneNumbers.first?.value.stringValue
@@ -88,7 +127,6 @@ class ContactsViewModel : ObservableObject {
}
} catch {
print("Unable to fetch contacts. \(error)")
}
}
@@ -97,6 +135,7 @@ class ContactsViewModel : ObservableObject {
// make sure userId is not the same as friendId...don't want people friending themselves
if userId == friendId {
completion(ServiceState.error(ServiceError(description: "You cannot friend yourself, silly!")))
self.toast = .cannotFriendYourself
return
}
@@ -8,6 +8,7 @@
import SwiftUI
import Contacts
import NavigationStack
import AlertToast
struct FindFriendsView: View {
@EnvironmentObject var navigationStack : NavigationStack
@@ -52,6 +53,9 @@ struct FindFriendsView: View {
.onAppear {
self.contactsVM.fetchContacts()
}
.toast(isPresenting: self.$contactsVM.showToast) {
self.contactsVM.toast?.view ?? AlertToast(displayMode: .hud, type: .error(Color.red), title: "Something went wrong")
}
}
var searchItems: [String] {
@@ -134,24 +138,28 @@ struct ListContactRow: View {
primaryButton: .default(Text("Cancel")),
secondaryButton: .default(Text("Confirm")) {
print("adding contact to circle")
// call method in vm to get it done, then navigate to the circle
if self.authSessionStore.friendsArr.count < 10 || self.authSessionStore.user?.phoneNumber == "+19499230445" {
self.contactsVM.addOrActivateFriendToCircle(userId: self.authSessionStore.user!.id!, friendId: (contact.user!.id)!) {res in
print(res)
switch res {
case .error(let err):
print(err)
case .success(let str):
print(str)
}
}
if self.authSessionStore.friendsArr.count >= 10 {
self.contactsVM.toast = .maxFriendsInCircle
return
}
self.contactsVM.addOrActivateFriendToCircle(userId: self.authSessionStore.user!.id!, friendId: (contact.user!.id)!) {res in
print(res)
self.navigationStack.push(InnerCircleView())
switch res {
case .error(let err):
print(err)
self.contactsVM.toast = .generalError
case .success(let str):
print(str)
self.contactsVM.toast = .addedFriend
self.navigationStack.push(InnerCircleView())
}
}
}
)
}
}
else { // invite button to text the person
HStack(alignment: .center, spacing: 0) {
@@ -43,11 +43,9 @@ struct CircleFooterView: View {
Button(role: .destructive) {
print("deactivating friend...removing from circle")
if self.authSessionStore.user?.id != nil && self.selectedFriendIndex != nil {
self.innerCircleVM.activateOrDeactiveInboxUser(activate: false, userId: self.authSessionStore.user!.id!, friendId: self.selectedFriendIndex!) {res in
print(res)
self.selectedFriendIndex = nil // making this footer disappear although a view change should do this
}
self.innerCircleVM.activateOrDeactiveInboxUser(activate: false, userId: self.authSessionStore.user!.id!, friendId: self.selectedFriendIndex!)
self.selectedFriendIndex = nil
}
} label: {
Label("Remove from Circle", systemImage: "person.crop.circle.fill.badge.minus")
@@ -131,7 +131,6 @@ struct CircleGridView: View {
else {
print("no convo id to join")
}
}
else {
self.convoVM.toast = .alreadyInCall
@@ -308,17 +307,17 @@ struct CircleGridView: View {
message: Text(self.alertSubtext),
primaryButton: .destructive(Text("Reject"), action: {
// create user friend but a rejected one
if self.authSessionStore.friendsArr.count < 10 || self.authSessionStore.user?.phoneNumber == "+19499230445" {
self.innerCircleVM.activateOrDeactiveInboxUser(activate: false, userId: self.authSessionStore.user!.id!, friendId: inboxUserId) { res in
print(res)
}
}
self.innerCircleVM.activateOrDeactiveInboxUser(activate: false, userId: self.authSessionStore.user!.id!, friendId: inboxUserId)
}),
secondaryButton: .default(Text("Add"), action: {
// create user friend
self.innerCircleVM.activateOrDeactiveInboxUser(activate: true, userId: self.authSessionStore.user!.id!, friendId: inboxUserId) { res in
print(res)
// create user friend if have space in circle
// TODO: view models should be able to do this validation, need some way of view models to speak to each other
if self.authSessionStore.friendsArr.count >= 10 {
self.innerCircleVM.toast = .maxFriendsInCircle
return
}
self.innerCircleVM.activateOrDeactiveInboxUser(activate: true, userId: self.authSessionStore.user!.id!, friendId: inboxUserId)
})
)
}
@@ -153,6 +153,9 @@ struct InnerCircleView: View {
.toast(isPresenting: self.$convoViewModel.showToast) {
self.convoViewModel.toast?.view ?? AlertToast(displayMode: .hud, type: .error(Color.red), title: "Something went wrong")
}
.toast(isPresenting: self.$innerCircleVM.showToast) {
self.innerCircleVM.toast?.view ?? AlertToast(displayMode: .hud, type: .error(Color.red), title: "Something went wrong")
}
// .onDisappear {
// print("deiniting data listeners, but current data should still be cached!")
//
@@ -7,8 +7,58 @@
import Foundation
import AVFoundation
import AlertToast
import SwiftUI
class InnerCircleViewModel: ObservableObject {
@Published var toast: Toast? {
didSet {
self.showToast = true
}
}
@Published var showToast: Bool = false
enum Toast: Identifiable {
var id: Self { self }
case startedClip
case problemSendingClip
case nothingRecorded
case clipSent
case maxFriendsInCircle
case cannotFriendYourself
case addedFriend
case removedFriend
case generalError
var view: AlertToast {
switch self {
case .removedFriend:
return AlertToast(displayMode: .hud, type: .complete(Color.green), title: "removed friend")
case .addedFriend:
return AlertToast(displayMode: .hud, type: .complete(Color.green), title: "added friend")
case .cannotFriendYourself:
return AlertToast(displayMode: .hud, type: .error(Color.orange), title: "silly! 🙉", subTitle: "you cannot friend yourself")
case .maxFriendsInCircle:
return AlertToast(displayMode: .hud, type: .systemImage("person.crop.circle.badge.exclamationmark.fill", Color.orange), title: "circle full!", subTitle: "tap on an existing friend and hold down on their icon in the bottom left to remove them to make space")
case .nothingRecorded:
return AlertToast(displayMode: .hud, type: .systemImage("exclamationmark.triangle.fill", NirvanaColor.teal), title: "nothing recorded", subTitle: "please try again")
case .clipSent:
return AlertToast(displayMode: .hud, type: .systemImage("paperplane.circle.fill", NirvanaColor.teal), title: "clip sent")
case .problemSendingClip:
return AlertToast(displayMode: .hud, type: .error(Color.orange), title: "problem sending clip", subTitle: "please try again")
case .startedClip:
return AlertToast(displayMode: .hud, type: .systemImage("waveform.circle.fill", NirvanaColor.teal), title: "clip started")
default:
return AlertToast(displayMode: .hud, type: .error(Color.orange), title: "Something went wrong ‼️")
}
}
}
var audioRecorder : AVAudioRecorder!
var audioPlayer : AVAudioPlayer!
@@ -21,7 +71,7 @@ class InnerCircleViewModel: ObservableObject {
private let cloudStorageService = CloudStorageService()
private let firestoreService = FirestoreService()
private let pushNotificationService = PushNotificationService()
private let agoraService = AgoraService()
init() {
// separate set up for listening vs recording
@@ -57,6 +107,8 @@ extension InnerCircleViewModel {
audioRecorder.record()
isRecording = true
self.toast = .startedClip
self.audioLocalUrl = filePath // setting this for later use when recording is stopped
} catch {
@@ -81,6 +133,7 @@ extension InnerCircleViewModel {
self.cloudStorageService.uploadLocalUrl(localFileUrl: self.audioLocalUrl!) {[weak self] audioDataUrl in
if audioDataUrl == nil {
print("there was an error in uploading file")
self?.toast = .problemSendingClip
return
}
@@ -90,18 +143,33 @@ extension InnerCircleViewModel {
self?.firestoreService.createMessage(message: newMessage) {[weak self] res in
print(res)
// sending push notification if there was a device token
if receiver.deviceToken != nil && receiver.nickname != nil {
self?.pushNotificationService.sendPushNotification(to: receiver.deviceToken!, title: "🌱Nirvana", body: "continue your conversation with \(sender.nickname ?? "your friend")")
switch res {
case .success:
self?.toast = .clipSent
// sending push notification if there was a device token for this friend
if receiver.deviceToken != nil && receiver.nickname != nil {
self?.pushNotificationService.sendPushNotification(to: receiver.deviceToken!, title: "🌱Nirvana", body: "continue your conversation with \(sender.nickname ?? "your friend")")
}
// delete local audio file from user's phone so that it doesn't take crazy space
print("stopped recording: file about to get deleted from \(self?.getTemporaryDirectory()) with filename: \(self?.audioLocalUrl)")
try? FileManager.default.removeItem(at: (self?.audioLocalUrl)!)
case .error(let err):
print(err)
self?.toast = .problemSendingClip
default:
self?.toast = .problemSendingClip
}
// delete local audio file from user's phone so that it doesn't get crazy
print("stopped recording: file about to get deleted from \(self?.getTemporaryDirectory()) with filename: \(self?.audioLocalUrl)")
try? FileManager.default.removeItem(at: (self?.audioLocalUrl)!)
}
}
}
else {
print("nothing recorded, can't send")
self.toast = .problemSendingClip
}
}
func getTemporaryDirectory() -> URL {
@@ -123,11 +191,12 @@ extension InnerCircleViewModel {
// handle activating or deactivating friends
extension InnerCircleViewModel {
func activateOrDeactiveInboxUser(activate: Bool, userId: String, friendId: String, completion: @escaping((_ state: ServiceState) -> ())) {
func activateOrDeactiveInboxUser(activate: Bool, userId: String, friendId: String) {
// validation
// make sure userId is not the same as friendId...don't want people friending themselves
if userId == friendId {
completion(ServiceState.error(ServiceError(description: "You cannot friend yourself, silly!")))
print("you cannot friend yourself")
self.toast = .cannotFriendYourself
return
}
@@ -135,7 +204,20 @@ extension InnerCircleViewModel {
var userFriend = UserFriends(userId: userId, friendId: friendId, isActive: activate, lastUpdatedTimestamp: nil)
self.firestoreService.createOrUpdateUserFriends(userFriend: userFriend, activateOrDeactivate: activate) {[weak self] res in
completion(res)
switch res {
case .success:
if activate {
self?.toast = .addedFriend
}
else {
self?.toast = .removedFriend
}
case .error(let err):
print(err)
self?.toast = .generalError
default:
self?.toast = .generalError
}
}
}
}
@@ -146,15 +228,3 @@ extension InnerCircleViewModel {
}
}
// everything related to calls and such
extension InnerCircleViewModel {
func getAgoraToken() {
if let uid = AuthSessionStore.getCurrentUserId() {
self.agoraService.getAgoraUserTokenServer(channelName: uid)
}
else {
print("no user authenticated to get an agora token")
}
}
}