Refactor toast system

This commit is contained in:
Benoit Martins 2026-01-20 13:32:21 +01:00
parent ac5a23bfff
commit 6b93a7ef5e
31 changed files with 156 additions and 199 deletions

View file

@ -106,12 +106,11 @@ class CoreContext: ObservableObject {
DispatchQueue.main.async {
if isConnected {
Log.info("Network is now satisfied")
ToastViewModel.shared.toastMessage = "Success_toast_network_connected"
ToastViewModel.shared.show("Success_toast_network_connected")
} else {
Log.error("Network is now \(path.status)")
ToastViewModel.shared.toastMessage = "Unavailable_network"
ToastViewModel.shared.show("Unavailable_network")
}
ToastViewModel.shared.displayToast = true
}
self.networkStatusIsConnected = isConnected
}
@ -317,14 +316,11 @@ class CoreContext: ObservableObject {
Log.info("[CoreContext] Transferred call \(transferred.remoteAddress!.asStringUriOnly()) state changed \(callState)")
DispatchQueue.main.async {
if callState == Call.State.Connected {
ToastViewModel.shared.toastMessage = "Success_toast_call_transfer_successful"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_toast_call_transfer_successful")
} else if callState == Call.State.OutgoingProgress {
ToastViewModel.shared.toastMessage = "Success_toast_call_transfer_in_progress"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_toast_call_transfer_in_progress")
} else if callState == Call.State.End || callState == Call.State.Error {
ToastViewModel.shared.toastMessage = "Failed_toast_call_transfer_failed"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_toast_call_transfer_failed")
}
}
}, onConfiguringStatus: { (_: Core, status: ConfiguringState, message: String) in
@ -345,8 +341,7 @@ class CoreContext: ObservableObject {
if info.starts(with: "https") {
DispatchQueue.main.async {
UIPasteboard.general.setValue(info, forPasteboardType: UTType.plainText.identifier)
ToastViewModel.shared.toastMessage = "Success_send_logs"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_send_logs")
}
}
}, onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
@ -396,8 +391,7 @@ class CoreContext: ObservableObject {
self.loggedIn = false
if self.networkStatusIsConnected {
// If network is disconnected, a toast message with key "Unavailable_network" should already be displayed
ToastViewModel.shared.toastMessage = "Registration_failed"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Registration_failed")
}
}

View file

@ -2,6 +2,6 @@ import Foundation
public enum AppGitInfo {
public static let branch = "feature/search_chat_message"
public static let commit = "50b9c69b6"
public static let commit = "ac5a23bff"
public static let tag = "6.1.0-alpha"
}

View file

@ -493,38 +493,36 @@ class TelecomManager: ObservableObject {
let isRecordingByRemoteTmp = call.remoteParams?.isRecording ?? false
if isRecordingByRemoteTmp && ToastViewModel.shared.toastMessage.isEmpty {
var displayName = ""
let friend = ContactsManager.shared.getFriendWithAddress(address: call.remoteAddress!)
if friend != nil && friend!.address != nil && friend!.address!.displayName != nil {
displayName = friend!.address!.displayName!
} else {
if call.remoteAddress!.displayName != nil {
displayName = call.remoteAddress!.displayName!
} else if call.remoteAddress!.username != nil {
displayName = call.remoteAddress!.username!
} else {
displayName = String(call.remoteAddress!.asStringUriOnly().dropFirst(4))
}
}
DispatchQueue.main.async {
self.isRecordingByRemote = isRecordingByRemoteTmp
ToastViewModel.shared.toastMessage = "\(displayName) is recording"
ToastViewModel.shared.displayToast = true
}
Log.info("[Call] Call is recording by \(call.remoteAddress!.asStringUriOnly())")
let displayName: String
let friend = ContactsManager.shared.getFriendWithAddress(address: call.remoteAddress)
if let name = friend?.address?.displayName {
displayName = name
} else if let name = call.remoteAddress?.displayName {
displayName = name
} else if let username = call.remoteAddress?.username {
displayName = username
} else if let uri = call.remoteAddress?.asStringUriOnly() {
displayName = String(uri.dropFirst(4))
} else {
displayName = "Unknown"
}
if !isRecordingByRemoteTmp && ToastViewModel.shared.toastMessage.contains("is recording") {
DispatchQueue.main.async {
self.isRecordingByRemote = isRecordingByRemoteTmp
ToastViewModel.shared.toastMessage = ""
ToastViewModel.shared.displayToast = false
DispatchQueue.main.async {
self.isRecordingByRemote = isRecordingByRemoteTmp
if isRecordingByRemoteTmp {
ToastViewModel.shared.show("\(displayName) is recording")
} else if let toast = ToastViewModel.shared.toast,
toast.message.contains("is recording") {
ToastViewModel.shared.hide()
}
Log.info("[Call] Recording is stopped by \(call.remoteAddress!.asStringUriOnly())")
}
if isRecordingByRemoteTmp {
Log.info("[Call] Call is recording by \(call.remoteAddress?.asStringUriOnly() ?? "")")
} else {
Log.info("[Call] Recording is stopped by \(call.remoteAddress?.asStringUriOnly() ?? "")")
}
if cstate == Call.State.PausedByRemote {

View file

@ -41,8 +41,7 @@ class AccountLoginViewModel: ObservableObject {
guard self.coreContext.networkStatusIsConnected else {
DispatchQueue.main.async {
self.coreContext.loggingInProgress = false
ToastViewModel.shared.toastMessage = "Unavailable_network"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Unavailable_network")
}
return
}

View file

@ -75,15 +75,18 @@ class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
core.stop()
try? core.start()
}
ToastViewModel.shared.toastMessage = "Success_qr_code_validated"
ToastViewModel.shared.displayToast = true
DispatchQueue.main.async {
ToastViewModel.shared.show("Success_qr_code_validated")
}
} else {
ToastViewModel.shared.toastMessage = "Invalide URI"
ToastViewModel.shared.displayToast.toggle()
DispatchQueue.main.async {
ToastViewModel.shared.show("Invalide URI")
}
}
} else {
ToastViewModel.shared.toastMessage = "Invalide URI"
ToastViewModel.shared.displayToast.toggle()
DispatchQueue.main.async {
ToastViewModel.shared.show("Invalide URI")
}
}
}
}

View file

@ -168,8 +168,7 @@ class RegisterViewModel: ObservableObject {
if !errorMessage.isEmpty {
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Error: \(errorMessage)"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Error: \(errorMessage)")
}
}
@ -341,8 +340,7 @@ class RegisterViewModel: ObservableObject {
DispatchQueue.main.async {
self.createInProgress = false
ToastViewModel.shared.toastMessage = "Failed_push_notification_not_received_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_push_notification_not_received_error")
}
}
@ -430,8 +428,7 @@ class RegisterViewModel: ObservableObject {
Log.error("\(RegisterViewModel.TAG) Account manager services hasn't been initialized!")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Failed_account_register_unexpected_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_account_register_unexpected_error")
}
}
}

View file

@ -672,8 +672,7 @@ struct CallView: View {
)
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_address_copied_into_clipboard")
}
}, label: {
HStack {

View file

@ -974,8 +974,7 @@ class CallViewModel: ObservableObject {
self.isNotEncrypted = false
if isDeviceTrusted && withToast {
ToastViewModel.shared.toastMessage = "Info_call_securised"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Info_call_securised")
}
}
@ -1058,8 +1057,9 @@ class CallViewModel: ObservableObject {
try callToTransferTo!.transferToAnother(dest: self.currentCall!)
Log.info("[CallViewModel] Attended transfer is successful")
} catch _ {
ToastViewModel.shared.toastMessage = "Failed_toast_call_transfer_failed"
ToastViewModel.shared.displayToast = true
DispatchQueue.main.async {
ToastViewModel.shared.show("Failed_toast_call_transfer_failed")
}
Log.error("[CallViewModel] Failed to make attended transfer!")
}
@ -1078,9 +1078,9 @@ class CallViewModel: ObservableObject {
try self.currentCall!.transferTo(referTo: toAddress)
Log.info("[CallViewModel] Blind call transfer is successful")
} catch _ {
ToastViewModel.shared.toastMessage = "Failed_toast_call_transfer_failed"
ToastViewModel.shared.displayToast = true
DispatchQueue.main.async {
ToastViewModel.shared.show("Failed_toast_call_transfer_failed")
}
Log.error("[CallViewModel] Failed to make blind call transfer!")
}
}
@ -1275,8 +1275,7 @@ class CallViewModel: ObservableObject {
)
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}
@ -1366,8 +1365,7 @@ class CallViewModel: ObservableObject {
self.chatRoomDelegate = nil
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in
@ -1401,8 +1399,7 @@ class CallViewModel: ObservableObject {
self.chatRoomDelegate = nil
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
})

View file

@ -66,8 +66,7 @@ struct ContactListBottomSheet: View {
dismiss()
}
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.show("Success_address_copied_into_clipboard")
} label: {
HStack {

View file

@ -91,8 +91,7 @@ class ContactsListViewModel: ObservableObject {
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
return
}
@ -137,8 +136,7 @@ class ContactsListViewModel: ObservableObject {
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
} else {
@ -168,8 +166,7 @@ class ContactsListViewModel: ObservableObject {
}
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in
@ -207,8 +204,7 @@ class ContactsListViewModel: ObservableObject {
}
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
})

View file

@ -1198,8 +1198,7 @@ struct ContentView: View {
self.isShowDeleteAllHistoryPopup.toggle()
sharedMainViewModel.displayedCall = nil
ToastViewModel.shared.toastMessage = "Success_remove_call_logs"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.show("Success_remove_call_logs")
},
titleThirdButton: Text("dialog_cancel"),
actionThirdButton: {

View file

@ -1393,8 +1393,7 @@ struct ConversationFragment: View {
forPasteboardType: UTType.plainText.identifier
)
ToastViewModel.shared.toastMessage = "Success_message_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_message_copied_into_clipboard")
conversationViewModel.selectedMessage = nil
} label: {

View file

@ -240,8 +240,7 @@ class ConversationModel: ObservableObject, Identifiable {
} else if state == .CreationFailed {
Log.error("\(ConversationModel.TAG) Failed to create group call!")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Failed_to_create_group_call_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_group_call_error")
}
}
})

View file

@ -134,8 +134,7 @@ class ConversationForwardMessageViewModel: ObservableObject {
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
return
}
@ -180,8 +179,7 @@ class ConversationForwardMessageViewModel: ObservableObject {
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
} else {
@ -211,8 +209,7 @@ class ConversationForwardMessageViewModel: ObservableObject {
self.chatRoomDelegate = nil
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in
@ -250,8 +247,7 @@ class ConversationForwardMessageViewModel: ObservableObject {
self.chatRoomDelegate = nil
DispatchQueue.main.async {
self.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
})

View file

@ -3013,8 +3013,9 @@ class ConversationViewModel: ObservableObject {
searchInProgress = false
if latestMatch == nil {
print("searchChatMessageAAA 22")
ToastViewModel.shared.toastMessage = "Failed_search_no_match_found"
ToastViewModel.shared.displayToast = true
DispatchQueue.main.async {
ToastViewModel.shared.show("Failed_search_no_match_found")
}
} else {
print("searchChatMessageAAA 33")
// Scroll to last matching event anyway, user may have scrolled away
@ -3029,8 +3030,9 @@ class ConversationViewModel: ObservableObject {
}
print("searchChatMessageAAA 33Bis")
}
ToastViewModel.shared.toastMessage = "Failed_search_results_limit_reached"
ToastViewModel.shared.displayToast = true
DispatchQueue.main.async {
ToastViewModel.shared.show("Failed_search_results_limit_reached")
}
}
}
}

View file

@ -149,8 +149,7 @@ class StartConversationViewModel: ObservableObject {
DispatchQueue.main.async {
self.operationGroupInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}
@ -206,8 +205,7 @@ class StartConversationViewModel: ObservableObject {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.operationOneToOneInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
return
}
@ -252,8 +250,7 @@ class StartConversationViewModel: ObservableObject {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.operationOneToOneInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
} else {
@ -284,8 +281,7 @@ class StartConversationViewModel: ObservableObject {
DispatchQueue.main.async {
self.operationOneToOneInProgress = false
self.operationGroupInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in
@ -314,8 +310,7 @@ class StartConversationViewModel: ObservableObject {
DispatchQueue.main.async {
self.operationOneToOneInProgress = false
self.operationGroupInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
})

View file

@ -32,8 +32,7 @@ class HelpView { // TODO (basic debug moved here until halp view is implemented)
CoreContext.shared.doOnCoreQueue { _ in
Core.resetLogCollection()
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "help_troubleshooting_debug_logs_cleaned_toast_message"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("help_troubleshooting_debug_logs_cleaned_toast_message")
}
}
}

View file

@ -25,39 +25,39 @@ struct ToastView: View {
var body: some View {
VStack {
if toastViewModel.displayToast {
if let toast = toastViewModel.toast {
HStack {
if toastViewModel.toastMessage.contains("Failed_search") {
if toast.message.contains("Failed_search") {
Image("magnifying-glass")
.resizable()
.renderingMode(.template)
.frame(width: 25, height: 25, alignment: .leading)
.foregroundStyle(Color.redDanger500)
} else if toastViewModel.toastMessage.contains("toast_call_transfer") {
} else if toast.message.contains("toast_call_transfer") {
Image("phone-transfer")
.resizable()
.renderingMode(.template)
.frame(width: 25, height: 25, alignment: .leading)
.foregroundStyle(toastViewModel.toastMessage.contains("Success") ? Color.greenSuccess500 : Color.redDanger500)
} else if toastViewModel.toastMessage.contains("is recording") {
.foregroundStyle(toast.message.contains("Success") ? Color.greenSuccess500 : Color.redDanger500)
} else if toast.message.contains("is recording") {
Image("record-fill")
.resizable()
.renderingMode(.template)
.frame(width: 25, height: 25, alignment: .leading)
.foregroundStyle(Color.redDanger500)
} else if toastViewModel.toastMessage.contains("Info_") {
} else if toast.message.contains("Info_") {
Image("trusted")
.resizable()
.frame(width: 25, height: 25, alignment: .leading)
} else {
Image(toastViewModel.toastMessage.contains("Success") ? "check" : "warning-circle")
Image(toast.message.contains("Success") ? "check" : "warning-circle")
.resizable()
.renderingMode(.template)
.frame(width: 25, height: 25, alignment: .leading)
.foregroundStyle(toastViewModel.toastMessage.contains("Success") ? Color.greenSuccess500 : Color.redDanger500)
.foregroundStyle(toast.message.contains("Success") ? Color.greenSuccess500 : Color.redDanger500)
}
switch toastViewModel.toastMessage {
switch toast.message {
case "Success_qr_code_validated":
Text("qr_code_validated")
.multilineTextAlignment(.center)
@ -122,7 +122,7 @@ struct ToastView: View {
.padding(8)
case let str where str.contains("is recording"):
Text(toastViewModel.toastMessage)
Text(toast.message)
.multilineTextAlignment(.center)
.foregroundStyle(Color.redDanger500)
.default_text_style(styleSize: 15)
@ -255,7 +255,7 @@ struct ToastView: View {
.padding(8)
case let str where str.contains("Error: "):
Text(toastViewModel.toastMessage)
Text(toast.message)
.multilineTextAlignment(.center)
.foregroundStyle(Color.redDanger500)
.default_text_style(styleSize: 15)
@ -371,26 +371,14 @@ struct ToastView: View {
.overlay(
RoundedRectangle(cornerRadius: 50)
.inset(by: 0.5)
.stroke(toastViewModel.toastMessage.contains("Success")
? Color.greenSuccess500 : (toastViewModel.toastMessage.contains("Info_")
.stroke(toast.message.contains("Success")
? Color.greenSuccess500 : (toast.message.contains("Info_")
? Color.blueInfo500 : Color.redDanger500), lineWidth: 1)
)
.onTapGesture {
if !toastViewModel.toastMessage.contains("is recording") {
if !toast.message.contains("is recording") {
withAnimation {
toastViewModel.toastMessage = ""
toastViewModel.displayToast = false
}
}
}
.onAppear {
print("toastMessagetoastMessage 00 \(toastViewModel.toastMessage) \(toastViewModel.displayToast)")
if !toastViewModel.toastMessage.contains("is recording") {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
toastViewModel.toastMessage = ""
toastViewModel.displayToast = false
}
toastViewModel.hide()
}
}
}

View file

@ -109,8 +109,7 @@ struct DebugFragment: View {
helpViewModel.version,
forPasteboardType: UTType.plainText.identifier
)
ToastViewModel.shared.toastMessage = "Success_text_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_text_copied_into_clipboard")
} label: {
HStack {
Image("app-store-logo")
@ -145,8 +144,7 @@ struct DebugFragment: View {
helpViewModel.sdkVersion,
forPasteboardType: UTType.plainText.identifier
)
ToastViewModel.shared.toastMessage = "Success_text_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_text_copied_into_clipboard")
} label: {
HStack {
Image("package")

View file

@ -92,14 +92,12 @@ class HelpViewModel: ObservableObject {
case .UpToDate:
Log.info("\(self.TAG): This version is up-to-date")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_version_up_to_date"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_version_up_to_date")
}
default:
Log.info("\(self.TAG): Can't check for update, an error happened [\(result)]")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Error")
}
}
}
@ -142,8 +140,7 @@ class HelpViewModel: ObservableObject {
Core.resetLogCollection()
Log.info("\(self.TAG) Debug logs have been cleaned")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_clear_logs"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_clear_logs")
}
}
}

View file

@ -120,8 +120,7 @@ struct HistoryContactFragment: View {
)
}
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.show("Success_address_copied_into_clipboard")
} label: {
HStack {

View file

@ -152,8 +152,7 @@ struct HistoryListBottomSheet: View {
dismiss()
}
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.show("Success_address_copied_into_clipboard")
} label: {
HStack {

View file

@ -280,8 +280,7 @@ class HistoryListViewModel: ObservableObject {
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
return
}
@ -326,8 +325,7 @@ class HistoryListViewModel: ObservableObject {
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
} else {
@ -357,8 +355,7 @@ class HistoryListViewModel: ObservableObject {
}
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
}, onConferenceJoined: { (chatRoom: ChatRoom, _: EventLog) in
@ -396,8 +393,7 @@ class HistoryListViewModel: ObservableObject {
}
DispatchQueue.main.async {
SharedMainViewModel.shared.operationInProgress = false
ToastViewModel.shared.toastMessage = "Failed_to_create_conversation_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_conversation_error")
}
}
})

View file

@ -139,8 +139,7 @@ class StartCallViewModel: ObservableObject {
} else if state == .CreationFailed {
Log.error("\(StartCallViewModel.TAG) Failed to create group call!")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Failed_to_create_group_call_error"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_to_create_group_call_error")
self.operationInProgress = false
}
}

View file

@ -199,8 +199,7 @@ struct MeetingFragment: View {
)
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_address_copied_into_clipboard")
}
}, label: {
HStack {

View file

@ -201,8 +201,7 @@ class MeetingViewModel: ObservableObject {
DispatchQueue.main.async {
self.operationInProgress = false
self.errorMsg = (SharedMainViewModel.shared.displayedMeeting != nil) ? "Could not edit conference" : "Could not create conference"
ToastViewModel.shared.toastMessage = (SharedMainViewModel.shared.displayedMeeting != nil) ? "meeting_failed_to_edit_toast" : "meeting_failed_to_schedule_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show((SharedMainViewModel.shared.displayedMeeting != nil) ? "meeting_failed_to_edit_toast" : "meeting_failed_to_schedule_toast")
}
} else if state == ConferenceScheduler.State.Ready {
if let confInfo = scheduler.info, let conferenceAddress = confInfo.uri {
@ -210,8 +209,7 @@ class MeetingViewModel: ObservableObject {
}
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Success_meeting_info_created_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_meeting_info_created_toast")
}
if SharedMainViewModel.shared.displayedMeeting != nil {
@ -243,8 +241,7 @@ class MeetingViewModel: ObservableObject {
} else if failedInvitations.count == self.participants.count {
Log.error("\(MeetingViewModel.TAG) No invitation sent!")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "meeting_failed_to_send_invites_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("meeting_failed_to_send_invites_toast")
}
} else {
var failInvList = ""
@ -256,8 +253,7 @@ class MeetingViewModel: ObservableObject {
}
Log.warn("\(MeetingViewModel.TAG) \(failedInvitations.count) invitations couldn't have been sent to: \(failInvList)")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "meeting_failed_to_send_part_of_invites_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("meeting_failed_to_send_part_of_invites_toast")
}
}
@ -273,16 +269,14 @@ class MeetingViewModel: ObservableObject {
guard !subject.isEmpty && !participants.isEmpty else {
Log.error("\(MeetingViewModel.TAG) Either no subject was set or no participant was selected, can't schedule meeting.")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Failed_no_subject_or_participant"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Failed_no_subject_or_participant")
}
return
}
guard CoreContext.shared.networkStatusIsConnected else {
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "Unavailable_network"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Unavailable_network")
}
return
}
@ -427,12 +421,10 @@ class MeetingViewModel: ObservableObject {
do {
try self.eventStore.save(event, span: .thisEvent)
Log.info("\(MeetingViewModel.TAG) Meeting '\(self.subject)' added to calendar")
ToastViewModel.shared.toastMessage = "Meeting_added_to_calendar"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Meeting_added_to_calendar")
} catch let error as NSError {
Log.error("\(MeetingViewModel.TAG) Failed to add meeting to calendar: \(error)")
ToastViewModel.shared.toastMessage = "Error: \(error)"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Error: \(error)")
}
} else {
Log.error("\(MeetingViewModel.TAG) Failed to add meeting to calendar: \(error?.localizedDescription ?? "")")

View file

@ -143,8 +143,7 @@ class MeetingsListViewModel: ObservableObject {
// Only remaining meeting is the fake TodayMeeting, remove it too
self.meetingsList.removeAll()
}
ToastViewModel.shared.toastMessage = "Success_toast_meeting_deleted"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_toast_meeting_deleted")
}
}
}
@ -180,8 +179,7 @@ class MeetingsListViewModel: ObservableObject {
}
Log.warn("\(MeetingViewModel.TAG) \(failedInvitations.count) invitations couldn't have been sent to: \(failInvList)")
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = "meeting_failed_to_send_part_of_invites_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("meeting_failed_to_send_part_of_invites_toast")
}
}
})

View file

@ -287,8 +287,7 @@ struct AccountProfileFragment: View {
forPasteboardType: UTType.plainText.identifier
)
ToastViewModel.shared.toastMessage = "Success_address_copied_into_clipboard"
ToastViewModel.shared.displayToast.toggle()
ToastViewModel.shared.show("Success_address_copied_into_clipboard")
}, label: {
Image("copy")
.resizable()

View file

@ -128,8 +128,7 @@ class CardDavViewModel: ObservableObject {
NotificationCenter.default.post(name: NSNotification.Name("ContactLoaded"), object: nil)
self.cardDavServerOperationSuccessful = true
ToastViewModel.shared.toastMessage = "Success_settings_contacts_carddav_deleted_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_settings_contacts_carddav_deleted_toast")
}
}
}
@ -227,8 +226,7 @@ class CardDavViewModel: ObservableObject {
DispatchQueue.main.async {
self.cardDavServerOperationInProgress = false
ToastViewModel.shared.toastMessage = "Success_settings_contacts_carddav_sync_successful_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("Success_settings_contacts_carddav_sync_successful_toast")
}
let name = self.displayName
@ -256,8 +254,7 @@ class CardDavViewModel: ObservableObject {
DispatchQueue.main.async {
self.cardDavServerOperationInProgress = false
ToastViewModel.shared.toastMessage = "settings_contacts_carddav_sync_error_toast"
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show("settings_contacts_carddav_sync_error_toast")
}
if !self.isEdit {
Log.error("\(CardDavViewModel.TAG) Synchronization failed, removing Friend list from Core")

View file

@ -19,13 +19,39 @@
import Foundation
class ToastViewModel: ObservableObject {
@MainActor
final class ToastViewModel: ObservableObject {
static let shared = ToastViewModel()
var toastMessage: String = ""
@Published var displayToast = false
@Published var toast: ToastData?
private init() {
private var hideWorkItem: DispatchWorkItem?
private init() {}
func show(_ message: String, duration: TimeInterval = 2.0) {
hideWorkItem?.cancel()
toast = ToastData(message: message)
let workItem = DispatchWorkItem { [weak self] in
self?.toast = nil
}
hideWorkItem = workItem
if !message.contains("is recording") {
DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: workItem)
}
}
func hide() {
hideWorkItem?.cancel()
toast = nil
}
}
struct ToastData: Identifiable, Equatable {
let id = UUID()
let message: String
}

View file

@ -170,8 +170,7 @@ class URIHandler {
private static func toast(_ message: String) {
DispatchQueue.main.async {
ToastViewModel.shared.toastMessage = message
ToastViewModel.shared.displayToast = true
ToastViewModel.shared.show(message)
}
}
}