diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 197e6ce00..f86ed2e68 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -450,6 +450,10 @@ 8491AF632AA20F9D00CC3E72 /* GliaViewControllerDelegateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491AF622AA20F9D00CC3E72 /* GliaViewControllerDelegateMock.swift */; }; 8491AF652AAB281500CC3E72 /* ChatViewModelTests+CustomCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491AF642AAB281500CC3E72 /* ChatViewModelTests+CustomCard.swift */; }; 8491AF672AB8707600CC3E72 /* ChatViewModelTests+Transferring.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491AF662AB8707600CC3E72 /* ChatViewModelTests+Transferring.swift */; }; + 8492F9152CAAE30F00242691 /* SecureConversations.ChatWithTranscriptModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8492F9142CAAE30F00242691 /* SecureConversations.ChatWithTranscriptModelTests.swift */; }; + 8492F9172CAD2F2000242691 /* TranscriptModelTests+ResponseCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8492F9162CAD2F2000242691 /* TranscriptModelTests+ResponseCard.swift */; }; + 8492F9192CAD329800242691 /* TranscriptModelTests+MessageRetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8492F9182CAD329800242691 /* TranscriptModelTests+MessageRetry.swift */; }; + 8492F91B2CAD6ADE00242691 /* ChatViewModelTests+MessageRetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8492F91A2CAD6ADE00242691 /* ChatViewModelTests+MessageRetry.swift */; }; 84A318A12869ECFC00CA1DE5 /* Unavailable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A318A02869ECFC00CA1DE5 /* Unavailable.swift */; }; 84C24CF82B8353A00089A388 /* ProcessInfoHandling.Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C24CF72B8353A00089A388 /* ProcessInfoHandling.Interface.swift */; }; 84C24CFA2B83541F0089A388 /* ProcessInfoHandling.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C24CF92B83541F0089A388 /* ProcessInfoHandling.Mock.swift */; }; @@ -880,35 +884,24 @@ C0D6C9F72C0D2F6D00D4709B /* AlertPlacement.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6C9F62C0D2F6D00D4709B /* AlertPlacement.swift */; }; C0D6C9FB2C0D2F9A00D4709B /* AlertInputType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6C9FA2C0D2F9A00D4709B /* AlertInputType.swift */; }; C0D6CA002C106A1F00D4709B /* AlertManager.Failing.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6C9FF2C106A1F00D4709B /* AlertManager.Failing.swift */; }; - C0D6CA232C1861F400D4709B /* VideoCallView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA222C1861F400D4709B /* VideoCallView.Environment.swift */; }; - C0D6CA3D2C19A82100D4709B /* VideoCallViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA3C2C19A82100D4709B /* VideoCallViewController.Environment.swift */; }; - C0D6CA0B2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0A2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift */; }; - C0D6CA0F2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0E2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift */; }; - C0D6CA112C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA102C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift */; }; - C0D6CA132C184DFF00D4709B /* FileDownloader.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA122C184DFF00D4709B /* FileDownloader.Environment.swift */; }; + C0D6CA052C172F8F00D4709B /* CallCoordinator.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA042C172F8F00D4709B /* CallCoordinator.Environment.swift */; }; + C0D6CA072C1843A900D4709B /* EngagementViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA062C1843A900D4709B /* EngagementViewController.Environment.swift */; }; + C0D6CA092C18451800D4709B /* CallViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA082C18451800D4709B /* CallViewController.Environment.swift */; }; C0D6CA0B2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0A2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift */; }; + C0D6CA0D2C1848E700D4709B /* GliaViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0C2C1848E700D4709B /* GliaViewController.Environment.swift */; }; C0D6CA0F2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0E2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift */; }; C0D6CA112C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA102C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift */; }; C0D6CA132C184DFF00D4709B /* FileDownloader.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA122C184DFF00D4709B /* FileDownloader.Environment.swift */; }; + C0D6CA152C184F1900D4709B /* SecureConversations.MessagesWithUnreadCountLoader.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA142C184F1900D4709B /* SecureConversations.MessagesWithUnreadCountLoader.Environment.swift */; }; C0D6CA172C18584E00D4709B /* SecureConversations.WelcomeView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA162C18584E00D4709B /* SecureConversations.WelcomeView.Environment.swift */; }; C0D6CA192C18590400D4709B /* UserImageView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA182C18590400D4709B /* UserImageView.Environment.swift */; }; - C0D6CA052C172F8F00D4709B /* CallCoordinator.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA042C172F8F00D4709B /* CallCoordinator.Environment.swift */; }; - C0D6CA072C1843A900D4709B /* EngagementViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA062C1843A900D4709B /* EngagementViewController.Environment.swift */; }; - C0D6CA092C18451800D4709B /* CallViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA082C18451800D4709B /* CallViewController.Environment.swift */; }; C0D6CA1B2C185BDE00D4709B /* EngagementView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA1A2C185BDE00D4709B /* EngagementView.Environment.swift */; }; C0D6CA1D2C185D2900D4709B /* CallView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA1C2C185D2900D4709B /* CallView.Environment.swift */; }; - C0D6CA0D2C1848E700D4709B /* GliaViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0C2C1848E700D4709B /* GliaViewController.Environment.swift */; }; C0D6CA1F2C185E3500D4709B /* BubbleView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA1E2C185E3500D4709B /* BubbleView.Environment.swift */; }; C0D6CA212C185F1000D4709B /* AlertTypeComposer.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA202C185F1000D4709B /* AlertTypeComposer.Environment.swift */; }; C0D6CA232C1861F400D4709B /* VideoCallView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA222C1861F400D4709B /* VideoCallView.Environment.swift */; }; C0D6CA252C1862C900D4709B /* AlertManager.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA242C1862C900D4709B /* AlertManager.Environment.swift */; }; C0D6CA272C18743E00D4709B /* CallDurationCounter.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA262C18743E00D4709B /* CallDurationCounter.Environment.swift */; }; - C0D6CA3F2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA3E2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift */; }; - C0D6CA412C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA402C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift */; }; - C0D6CA3F2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA3E2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift */; }; - C0D6CA412C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA402C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift */; }; - C0D6CA432C19AA0900D4709B /* SecureConversations.MessageTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA422C19AA0900D4709B /* SecureConversations.MessageTextView.swift */; }; - C0D6CA452C19AA8000D4709B /* SecureConversations.MessageTextView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA442C19AA8000D4709B /* SecureConversations.MessageTextView.Environment.swift */; }; C0D6CA292C199A4700D4709B /* UnreadMessageIndicatorView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA282C199A4700D4709B /* UnreadMessageIndicatorView.Environment.swift */; }; C0D6CA2B2C19A0E800D4709B /* OperatorChatMessageView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA2A2C19A0E800D4709B /* OperatorChatMessageView.Environment.swift */; }; C0D6CA2D2C19A19000D4709B /* ChoiceCardView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA2C2C19A19000D4709B /* ChoiceCardView.Environment.swift */; }; @@ -919,41 +912,26 @@ C0D6CA372C19A4EB00D4709B /* GvaPersistentButtonView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA362C19A4EB00D4709B /* GvaPersistentButtonView.Environment.swift */; }; C0D6CA392C19A57200D4709B /* ChatMessageEntryView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA382C19A57200D4709B /* ChatMessageEntryView.Environment.swift */; }; C0D6CA3B2C19A61900D4709B /* ChatMessageView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA3A2C19A61900D4709B /* ChatMessageView.Environment.swift */; }; - C0D6CA272C18743E00D4709B /* CallDurationCounter.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA262C18743E00D4709B /* CallDurationCounter.Environment.swift */; }; - C0D6CA472C19B35B00D4709B /* BubbleWindow.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA462C19B35B00D4709B /* BubbleWindow.Environment.swift */; }; - C0D6CA0B2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0A2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift */; }; - C0D6CA0F2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA0E2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift */; }; - C0D6CA112C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA102C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift */; }; - C0D6CA152C184F1900D4709B /* SecureConversations.MessagesWithUnreadCountLoader.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA142C184F1900D4709B /* SecureConversations.MessagesWithUnreadCountLoader.Environment.swift */; }; - C0D6CA172C18584E00D4709B /* SecureConversations.WelcomeView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA162C18584E00D4709B /* SecureConversations.WelcomeView.Environment.swift */; }; + C0D6CA3D2C19A82100D4709B /* VideoCallViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA3C2C19A82100D4709B /* VideoCallViewController.Environment.swift */; }; C0D6CA3F2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA3E2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift */; }; C0D6CA412C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA402C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift */; }; C0D6CA432C19AA0900D4709B /* SecureConversations.MessageTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA422C19AA0900D4709B /* SecureConversations.MessageTextView.swift */; }; C0D6CA452C19AA8000D4709B /* SecureConversations.MessageTextView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA442C19AA8000D4709B /* SecureConversations.MessageTextView.Environment.swift */; }; - C0D6CA532C19BC0300D4709B /* FilePreviewView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA522C19BC0300D4709B /* FilePreviewView.Environment.swift */; }; - C0D6CA552C19BCDB00D4709B /* SecureConversations.FilePreviewView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA542C19BCDB00D4709B /* SecureConversations.FilePreviewView.Environment.swift */; }; - C0D6CA5B2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5A2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift */; }; - C0D6CA5F2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5E2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift */; }; + C0D6CA472C19B35B00D4709B /* BubbleWindow.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA462C19B35B00D4709B /* BubbleWindow.Environment.swift */; }; C0D6CA492C19B64700D4709B /* ImageView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA482C19B64700D4709B /* ImageView.Environment.swift */; }; C0D6CA4B2C19B6D100D4709B /* GvaGalleryListView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA4A2C19B6D100D4709B /* GvaGalleryListView.Environment.swift */; }; C0D6CA4D2C19B86000D4709B /* OnHoldOverlayView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA4C2C19B86000D4709B /* OnHoldOverlayView.Environment.swift */; }; - C0D6CA5D2C19C07200D4709B /* ConnectOperatorView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5C2C19C07200D4709B /* ConnectOperatorView.Environment.swift */; }; - C0D6CA5F2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5E2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift */; }; + C0D6CA4F2C19B9A300D4709B /* GliaPresenter.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA4E2C19B9A300D4709B /* GliaPresenter.Environment.swift */; }; + C0D6CA512C19BB5600D4709B /* SurveyViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA502C19BB5600D4709B /* SurveyViewController.Environment.swift */; }; C0D6CA532C19BC0300D4709B /* FilePreviewView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA522C19BC0300D4709B /* FilePreviewView.Environment.swift */; }; C0D6CA552C19BCDB00D4709B /* SecureConversations.FilePreviewView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA542C19BCDB00D4709B /* SecureConversations.FilePreviewView.Environment.swift */; }; C0D6CA572C19BDCD00D4709B /* FilePickerViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA562C19BDCD00D4709B /* FilePickerViewModel.Environment.swift */; }; C0D6CA592C19BE9D00D4709B /* FilePickerController.Envrionment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA582C19BE9D00D4709B /* FilePickerController.Envrionment.swift */; }; - C0D6CA4D2C19B86000D4709B /* OnHoldOverlayView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA4C2C19B86000D4709B /* OnHoldOverlayView.Environment.swift */; }; + C0D6CA5B2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5A2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift */; }; C0D6CA5D2C19C07200D4709B /* ConnectOperatorView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5C2C19C07200D4709B /* ConnectOperatorView.Environment.swift */; }; + C0D6CA5F2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5E2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift */; }; C0D6CA612C19C4D900D4709B /* OnHoldOverlayVisualEffectView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA602C19C4D900D4709B /* OnHoldOverlayVisualEffectView.Environment.swift */; }; - C0D6CA612C19C4D900D4709B /* OnHoldOverlayVisualEffectView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA602C19C4D900D4709B /* OnHoldOverlayVisualEffectView.Environment.swift */; }; - C0D6CA4F2C19B9A300D4709B /* GliaPresenter.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA4E2C19B9A300D4709B /* GliaPresenter.Environment.swift */; }; - C0D6CA512C19BB5600D4709B /* SurveyViewController.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA502C19BB5600D4709B /* SurveyViewController.Environment.swift */; }; - C0D6CA532C19BC0300D4709B /* FilePreviewView.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA522C19BC0300D4709B /* FilePreviewView.Environment.swift */; }; C0D6CA632C19C59100D4709B /* Glia.OpaqueAuthentication.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA622C19C59100D4709B /* Glia.OpaqueAuthentication.Environment.swift */; }; - C0D6CA572C19BDCD00D4709B /* FilePickerViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA562C19BDCD00D4709B /* FilePickerViewModel.Environment.swift */; }; - C0D6CA592C19BE9D00D4709B /* FilePickerController.Envrionment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA582C19BE9D00D4709B /* FilePickerController.Envrionment.swift */; }; - C0D6CA5B2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D6CA5A2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift */; }; C0E948042AB1D5D200890026 /* ActionButtonSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E948032AB1D5D200890026 /* ActionButtonSwiftUI.swift */; }; C0E948062AB1D64700890026 /* HeaderButtonSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E948052AB1D64700890026 /* HeaderButtonSwiftUI.swift */; }; C0E948092AB1D6AB00890026 /* HeaderSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E948082AB1D6AB00890026 /* HeaderSwiftUI.swift */; }; @@ -1484,6 +1462,10 @@ 8491AF622AA20F9D00CC3E72 /* GliaViewControllerDelegateMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GliaViewControllerDelegateMock.swift; sourceTree = ""; }; 8491AF642AAB281500CC3E72 /* ChatViewModelTests+CustomCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatViewModelTests+CustomCard.swift"; sourceTree = ""; }; 8491AF662AB8707600CC3E72 /* ChatViewModelTests+Transferring.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatViewModelTests+Transferring.swift"; sourceTree = ""; }; + 8492F9142CAAE30F00242691 /* SecureConversations.ChatWithTranscriptModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.ChatWithTranscriptModelTests.swift; sourceTree = ""; }; + 8492F9162CAD2F2000242691 /* TranscriptModelTests+ResponseCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TranscriptModelTests+ResponseCard.swift"; sourceTree = ""; }; + 8492F9182CAD329800242691 /* TranscriptModelTests+MessageRetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TranscriptModelTests+MessageRetry.swift"; sourceTree = ""; }; + 8492F91A2CAD6ADE00242691 /* ChatViewModelTests+MessageRetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatViewModelTests+MessageRetry.swift"; sourceTree = ""; }; 84A318A02869ECFC00CA1DE5 /* Unavailable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Unavailable.swift; sourceTree = ""; }; 84C24CF72B8353A00089A388 /* ProcessInfoHandling.Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessInfoHandling.Interface.swift; sourceTree = ""; }; 84C24CF92B83541F0089A388 /* ProcessInfoHandling.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessInfoHandling.Mock.swift; sourceTree = ""; }; @@ -1921,29 +1903,15 @@ C0D6C9F62C0D2F6D00D4709B /* AlertPlacement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPlacement.swift; sourceTree = ""; }; C0D6C9FA2C0D2F9A00D4709B /* AlertInputType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertInputType.swift; sourceTree = ""; }; C0D6C9FF2C106A1F00D4709B /* AlertManager.Failing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertManager.Failing.swift; sourceTree = ""; }; - C0D6CA0A2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.Coordinator.Environment.swift; sourceTree = ""; }; - C0D6CA0E2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewModel.Environment.swift; sourceTree = ""; }; - C0D6CA102C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewController.Environment.swift; sourceTree = ""; }; - C0D6CA142C184F1900D4709B /* SecureConversations.MessagesWithUnreadCountLoader.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.MessagesWithUnreadCountLoader.Environment.swift; sourceTree = ""; }; - C0D6CA162C18584E00D4709B /* SecureConversations.WelcomeView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeView.Environment.swift; sourceTree = ""; }; - C0D6CA3E2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadView.Environment.swift; sourceTree = ""; }; - C0D6CA402C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadListView.Environment.swift; sourceTree = ""; }; - C0D6CA422C19AA0900D4709B /* SecureConversations.MessageTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.MessageTextView.swift; sourceTree = ""; }; - C0D6CA442C19AA8000D4709B /* SecureConversations.MessageTextView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.MessageTextView.Environment.swift; sourceTree = ""; }; - C0D6CA522C19BC0300D4709B /* FilePreviewView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewView.Environment.swift; sourceTree = ""; }; - C0D6CA542C19BCDB00D4709B /* SecureConversations.FilePreviewView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FilePreviewView.Environment.swift; sourceTree = ""; }; - C0D6CA5A2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.ConfirmationViewModel.Environment.swift; sourceTree = ""; }; - C0D6CA5E2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatFileDownloadContentView.Environment.swift; sourceTree = ""; }; - C0D6CA182C18590400D4709B /* UserImageView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserImageView.Environment.swift; sourceTree = ""; }; C0D6CA042C172F8F00D4709B /* CallCoordinator.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallCoordinator.Environment.swift; sourceTree = ""; }; C0D6CA062C1843A900D4709B /* EngagementViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EngagementViewController.Environment.swift; sourceTree = ""; }; C0D6CA082C18451800D4709B /* CallViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallViewController.Environment.swift; sourceTree = ""; }; - C0D6CA1A2C185BDE00D4709B /* EngagementView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EngagementView.Environment.swift; sourceTree = ""; }; - C0D6CA1C2C185D2900D4709B /* CallView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallView.Environment.swift; sourceTree = ""; }; + C0D6CA0A2C18472400D4709B /* SecureConversations.Coordinator.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.Coordinator.Environment.swift; sourceTree = ""; }; C0D6CA0C2C1848E700D4709B /* GliaViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GliaViewController.Environment.swift; sourceTree = ""; }; C0D6CA0E2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewModel.Environment.swift; sourceTree = ""; }; C0D6CA102C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewController.Environment.swift; sourceTree = ""; }; C0D6CA122C184DFF00D4709B /* FileDownloader.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDownloader.Environment.swift; sourceTree = ""; }; + C0D6CA142C184F1900D4709B /* SecureConversations.MessagesWithUnreadCountLoader.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.MessagesWithUnreadCountLoader.Environment.swift; sourceTree = ""; }; C0D6CA162C18584E00D4709B /* SecureConversations.WelcomeView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeView.Environment.swift; sourceTree = ""; }; C0D6CA182C18590400D4709B /* UserImageView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserImageView.Environment.swift; sourceTree = ""; }; C0D6CA1A2C185BDE00D4709B /* EngagementView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EngagementView.Environment.swift; sourceTree = ""; }; @@ -1953,12 +1921,6 @@ C0D6CA222C1861F400D4709B /* VideoCallView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallView.Environment.swift; sourceTree = ""; }; C0D6CA242C1862C900D4709B /* AlertManager.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertManager.Environment.swift; sourceTree = ""; }; C0D6CA262C18743E00D4709B /* CallDurationCounter.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallDurationCounter.Environment.swift; sourceTree = ""; }; - C0D6CA0E2C184AB700D4709B /* SecureConversations.WelcomeViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewModel.Environment.swift; sourceTree = ""; }; - C0D6CA102C184CCA00D4709B /* SecureConversations.WelcomeViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewController.Environment.swift; sourceTree = ""; }; - C0D6CA122C184DFF00D4709B /* FileDownloader.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileDownloader.Environment.swift; sourceTree = ""; }; - C0D6CA222C1861F400D4709B /* VideoCallView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallView.Environment.swift; sourceTree = ""; }; - C0D6CA3C2C19A82100D4709B /* VideoCallViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallViewController.Environment.swift; sourceTree = ""; }; - C0D6CA1E2C185E3500D4709B /* BubbleView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleView.Environment.swift; sourceTree = ""; }; C0D6CA282C199A4700D4709B /* UnreadMessageIndicatorView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadMessageIndicatorView.Environment.swift; sourceTree = ""; }; C0D6CA2A2C19A0E800D4709B /* OperatorChatMessageView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatorChatMessageView.Environment.swift; sourceTree = ""; }; C0D6CA2C2C19A19000D4709B /* ChoiceCardView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChoiceCardView.Environment.swift; sourceTree = ""; }; @@ -1969,31 +1931,25 @@ C0D6CA362C19A4EB00D4709B /* GvaPersistentButtonView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaPersistentButtonView.Environment.swift; sourceTree = ""; }; C0D6CA382C19A57200D4709B /* ChatMessageEntryView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageEntryView.Environment.swift; sourceTree = ""; }; C0D6CA3A2C19A61900D4709B /* ChatMessageView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageView.Environment.swift; sourceTree = ""; }; + C0D6CA3C2C19A82100D4709B /* VideoCallViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallViewController.Environment.swift; sourceTree = ""; }; C0D6CA3E2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadView.Environment.swift; sourceTree = ""; }; C0D6CA402C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadListView.Environment.swift; sourceTree = ""; }; C0D6CA422C19AA0900D4709B /* SecureConversations.MessageTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.MessageTextView.swift; sourceTree = ""; }; C0D6CA442C19AA8000D4709B /* SecureConversations.MessageTextView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.MessageTextView.Environment.swift; sourceTree = ""; }; - C0D6CA3E2C19A8DA00D4709B /* SecureConversations.FileUploadView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadView.Environment.swift; sourceTree = ""; }; - C0D6CA402C19A97100D4709B /* SecureConversations.FileUploadListView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadListView.Environment.swift; sourceTree = ""; }; - C0D6CA262C18743E00D4709B /* CallDurationCounter.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallDurationCounter.Environment.swift; sourceTree = ""; }; C0D6CA462C19B35B00D4709B /* BubbleWindow.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleWindow.Environment.swift; sourceTree = ""; }; C0D6CA482C19B64700D4709B /* ImageView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageView.Environment.swift; sourceTree = ""; }; C0D6CA4A2C19B6D100D4709B /* GvaGalleryListView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaGalleryListView.Environment.swift; sourceTree = ""; }; - C0D6CA5C2C19C07200D4709B /* ConnectOperatorView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectOperatorView.Environment.swift; sourceTree = ""; }; - C0D6CA522C19BC0300D4709B /* FilePreviewView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewView.Environment.swift; sourceTree = ""; }; - C0D6CA562C19BDCD00D4709B /* FilePickerViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePickerViewModel.Environment.swift; sourceTree = ""; }; - C0D6CA582C19BE9D00D4709B /* FilePickerController.Envrionment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePickerController.Envrionment.swift; sourceTree = ""; }; - C0D6CA5A2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.ConfirmationViewModel.Environment.swift; sourceTree = ""; }; + C0D6CA4C2C19B86000D4709B /* OnHoldOverlayView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnHoldOverlayView.Environment.swift; sourceTree = ""; }; + C0D6CA4E2C19B9A300D4709B /* GliaPresenter.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GliaPresenter.Environment.swift; sourceTree = ""; }; + C0D6CA502C19BB5600D4709B /* SurveyViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyViewController.Environment.swift; sourceTree = ""; }; C0D6CA522C19BC0300D4709B /* FilePreviewView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePreviewView.Environment.swift; sourceTree = ""; }; C0D6CA542C19BCDB00D4709B /* SecureConversations.FilePreviewView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FilePreviewView.Environment.swift; sourceTree = ""; }; C0D6CA562C19BDCD00D4709B /* FilePickerViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePickerViewModel.Environment.swift; sourceTree = ""; }; C0D6CA582C19BE9D00D4709B /* FilePickerController.Envrionment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilePickerController.Envrionment.swift; sourceTree = ""; }; - C0D6CA4C2C19B86000D4709B /* OnHoldOverlayView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnHoldOverlayView.Environment.swift; sourceTree = ""; }; - C0D6CA4C2C19B86000D4709B /* OnHoldOverlayView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnHoldOverlayView.Environment.swift; sourceTree = ""; }; + C0D6CA5A2C19BF1D00D4709B /* SecureConversations.ConfirmationViewModel.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.ConfirmationViewModel.Environment.swift; sourceTree = ""; }; C0D6CA5C2C19C07200D4709B /* ConnectOperatorView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectOperatorView.Environment.swift; sourceTree = ""; }; + C0D6CA5E2C19C34F00D4709B /* ChatFileDownloadContentView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatFileDownloadContentView.Environment.swift; sourceTree = ""; }; C0D6CA602C19C4D900D4709B /* OnHoldOverlayVisualEffectView.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnHoldOverlayVisualEffectView.Environment.swift; sourceTree = ""; }; - C0D6CA4E2C19B9A300D4709B /* GliaPresenter.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GliaPresenter.Environment.swift; sourceTree = ""; }; - C0D6CA502C19BB5600D4709B /* SurveyViewController.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurveyViewController.Environment.swift; sourceTree = ""; }; C0D6CA622C19C59100D4709B /* Glia.OpaqueAuthentication.Environment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glia.OpaqueAuthentication.Environment.swift; sourceTree = ""; }; C0E948032AB1D5D200890026 /* ActionButtonSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButtonSwiftUI.swift; sourceTree = ""; }; C0E948052AB1D64700890026 /* HeaderButtonSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderButtonSwiftUI.swift; sourceTree = ""; }; @@ -3279,6 +3235,8 @@ AF29810829E045CE0005BD55 /* TranscriptModelTests.swift */, 8491AF4F2A9CBB0400CC3E72 /* TranscriptModelTests+GVA.swift */, 8491AF5F2AA1EBB600CC3E72 /* TranscriptModelTests+URLs.swift */, + 8492F9162CAD2F2000242691 /* TranscriptModelTests+ResponseCard.swift */, + 8492F9182CAD329800242691 /* TranscriptModelTests+MessageRetry.swift */, ); path = ChatTranscript; sourceTree = ""; @@ -4045,6 +4003,7 @@ 84681A942A61844000DD7406 /* ChatViewModelTests+Gva.swift */, 8491AF642AAB281500CC3E72 /* ChatViewModelTests+CustomCard.swift */, 8491AF662AB8707600CC3E72 /* ChatViewModelTests+Transferring.swift */, + 8492F91A2CAD6ADE00242691 /* ChatViewModelTests+MessageRetry.swift */, ); path = ChatViewModel; sourceTree = ""; @@ -4231,6 +4190,14 @@ path = Mocks; sourceTree = ""; }; + 8492F9132CAAE2D600242691 /* SecureConversations.ChatWithTranscriptModel */ = { + isa = PBXGroup; + children = ( + 8492F9142CAAE30F00242691 /* SecureConversations.ChatWithTranscriptModelTests.swift */, + ); + path = SecureConversations.ChatWithTranscriptModel; + sourceTree = ""; + }; 84C24CF62B8353840089A388 /* ProcessInfoHandling */ = { isa = PBXGroup; children = ( @@ -4500,6 +4467,7 @@ AFEF5C7229929A73005C3D8D /* SecureConversations */ = { isa = PBXGroup; children = ( + 8492F9132CAAE2D600242691 /* SecureConversations.ChatWithTranscriptModel */, 31B277FF2B558F010021DEC1 /* Coordinator */, 31D286AB2A00DA5F009192A6 /* Confirmation */, 3142696829FFB4ED003DF62E /* ChatTranscript */, @@ -6347,12 +6315,15 @@ 9A19927027D3BCAE00161AAE /* GCD.Failing.swift in Sources */, 3142696A29FFB712003DF62E /* Interactor.Failing.swift in Sources */, 8485704F2BEE3A0800CEBCC5 /* ChatViewTest.swift in Sources */, + 8492F9152CAAE30F00242691 /* SecureConversations.ChatWithTranscriptModelTests.swift in Sources */, + 8492F9192CAD329800242691 /* TranscriptModelTests+MessageRetry.swift in Sources */, 8491AF602AA1EBB600CC3E72 /* TranscriptModelTests+URLs.swift in Sources */, 9A8130C427D9099F00220BBD /* FileDownload.Environment.Failing.swift in Sources */, 3117EBA22B9B041100F520D8 /* (null) in Sources */, 31CCE3E52BCE8F3A00F92535 /* CallVisualizer.Coordinator.Environment.Mock.swift in Sources */, 31CCE3E72BCE8F3A00F92535 /* VisitorCodeCoordinatorTests.swift in Sources */, AF29811029E06E830005BD55 /* Availability.Environment.Failing.swift in Sources */, + 8492F91B2CAD6ADE00242691 /* ChatViewModelTests+MessageRetry.swift in Sources */, AF9C0C442BC5A29B00C25E47 /* GliaPresenterTests.swift in Sources */, 8464297A2A44937600943BD6 /* AlertViewControllerTests.swift in Sources */, AFCF8A5A2A02A97100B7ABB3 /* ChatItemTests.swift in Sources */, @@ -6399,6 +6370,7 @@ 9A1992E727D66C7400161AAE /* UIKitBased.Failing.swift in Sources */, 31FF0DCB2B5907C600834AFB /* ChatCoordinatorTests.swift in Sources */, 3146C9432AB1851C0047D8CC /* LocalizationTests.swift in Sources */, + 8492F9172CAD2F2000242691 /* TranscriptModelTests+ResponseCard.swift in Sources */, 3115EFBA2BC960B500B24D5A /* (null) in Sources */, 31CCE3E62BCE8F3A00F92535 /* ScreenSharingCoordinatorTests.swift in Sources */, 846A5C3929D18D400049B29F /* ScreenShareHandlerTests.swift in Sources */, diff --git a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.ChatWithTranscriptModel.swift b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.ChatWithTranscriptModel.swift index 96b4d5813..89be400ca 100644 --- a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.ChatWithTranscriptModel.swift +++ b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.ChatWithTranscriptModel.swift @@ -311,7 +311,6 @@ extension SecureConversations.ChatWithTranscriptModel { } // swiftlint:enable function_body_length - // TODO: - This will be covered with unit tests in next PR static func markMessageAsFailed( _ outgoingMessage: OutgoingMessage, in section: Section, @@ -336,7 +335,6 @@ extension SecureConversations.ChatWithTranscriptModel { action?(.refreshRows([index], in: section.index, animated: false)) } - // TODO: - This will be covered with unit tests in next PR static func removeMessage( _ outgoingMessage: OutgoingMessage, in section: Section, diff --git a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.GVA.swift b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.GVA.swift index 3c2c52a76..062c256d7 100644 --- a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.GVA.swift +++ b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.GVA.swift @@ -119,7 +119,10 @@ private extension SecureConversations.TranscriptModel { in: self.pendingSection ) case let .failure(error): - self.engagementAction?(.showAlert(.error(error: error))) + self.markMessageAsFailed( + outgoingMessage, + in: self.pendingSection + ) } } } diff --git a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift index 3a29c149f..77140526a 100644 --- a/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift +++ b/GliaWidgets/SecureConversations/ChatTranscript/SecureConversations.TranscriptModel.swift @@ -77,7 +77,8 @@ extension SecureConversations { private(set) var receivedMessages = [String: [MessageSource]]() - let deliveredStatusText: String + private let deliveredStatusText: String + private let failedToDeliverStatusText: String var numberOfSections: Int { sections.count @@ -90,6 +91,7 @@ extension SecureConversations { environment: Environment, availability: Availability, deliveredStatusText: String, + failedToDeliverStatusText: String, interactor: Interactor ) { self.isCustomCardSupported = isCustomCardSupported @@ -98,6 +100,7 @@ extension SecureConversations { self.availability = availability self.deliveredStatusText = deliveredStatusText + self.failedToDeliverStatusText = failedToDeliverStatusText self.interactor = interactor self.hasViewAppeared = false let uploader = FileUploader( @@ -212,8 +215,7 @@ extension SecureConversations { case let .gvaButtonTapped(option): gvaOptionAction(for: option)() case let .retryMessageTapped(message): - // Will be handled in next PR - break + retryMessageSending(message) } } @@ -281,8 +283,11 @@ extension SecureConversations.TranscriptModel { switch result { case let .success(message): self.receiveMessage(from: .api(message, outgoingMessage: outgoingMessage)) - case let .failure(error): - self.engagementAction?(.showAlert(.error(error: error))) + case .failure: + self.markMessageAsFailed( + outgoingMessage, + in: self.pendingSection + ) } } @@ -316,6 +321,36 @@ extension SecureConversations.TranscriptModel { } } +// MARK: Message sending retry +extension SecureConversations.TranscriptModel { + private func retryMessageSending(_ outgoingMessage: OutgoingMessage) { + removeMessage( + outgoingMessage, + in: pendingSection + ) + + let item = ChatItem(with: outgoingMessage) + appendItem(item, to: pendingSection, animated: true) + action?(.scrollToBottom(animated: true)) + + _ = environment.sendSecureMessagePayload( + outgoingMessage.payload, + environment.queueIds + ) { [weak self] result in + guard let self = self else { return } + switch result { + case let .success(message): + self.receiveMessage(from: .api(message, outgoingMessage: outgoingMessage)) + case .failure: + self.markMessageAsFailed( + outgoingMessage, + in: self.pendingSection + ) + } + } + } +} + // MARK: Section management extension SecureConversations.TranscriptModel { func appendItem( @@ -367,6 +402,29 @@ extension SecureConversations.TranscriptModel { guard environment.uiApplication.canOpenURL(url) else { return } environment.uiApplication.open(url) } + + func markMessageAsFailed( + _ outgoingMessage: OutgoingMessage, + in section: Section + ) { + SecureConversations.ChatWithTranscriptModel.markMessageAsFailed( + outgoingMessage, + in: section, + message: failedToDeliverStatusText, + action: action + ) + } + + func removeMessage( + _ outgoingMessage: OutgoingMessage, + in section: Section + ) { + SecureConversations.ChatWithTranscriptModel.removeMessage( + outgoingMessage, + in: section, + action: action + ) + } } // MARK: Handling of file-picker diff --git a/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift b/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift index 3d1e7de97..ee9cb2464 100644 --- a/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift +++ b/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift @@ -236,6 +236,7 @@ extension ChatCoordinator { ), availability: .init(environment: .create(with: environment)), deliveredStatusText: viewFactory.theme.chat.visitorMessageStyle.delivered, + failedToDeliverStatusText: viewFactory.theme.chat.visitorMessageStyle.failedToDeliver, interactor: interactor ) diff --git a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ChoiceCards.swift b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ChoiceCards.swift index c8abbdbcc..b87a4350a 100644 --- a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ChoiceCards.swift +++ b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel+ChoiceCards.swift @@ -12,9 +12,18 @@ extension ChatViewModel { imageUrl: nil ) - let payload = self.environment.createSendMessagePayload(text, attachment) + let payload = environment.createSendMessagePayload(text, attachment) registerReceivedMessage(messageId: payload.messageId.rawValue) + let outgoingMessage = OutgoingMessage( + payload: payload, + relation: .singleChoice(messageId: .init(rawValue: messageId)) + ) + + let item = ChatItem(with: outgoingMessage) + appendItem(item, to: messagesSection, animated: true) + action?(.scrollToBottom(animated: true)) + interactor.send(messagePayload: payload) { [weak self] result in guard let self = self else { return } @@ -22,8 +31,11 @@ extension ChatViewModel { case .success(let message): let selection = message.content self.respond(to: messageId, with: selection) - case let .failure(error): - self.engagementAction?(.showAlert(.error(error: error.error))) + case .failure: + self.markMessageAsFailed( + outgoingMessage, + in: self.messagesSection + ) } } } @@ -52,16 +64,17 @@ extension ChatViewModel { message.attachment?.selectedOption = selection let item = ChatItem( - kind: .visitorMessage( + kind: .operatorMessage( ChatMessage( id: message.id, operator: message.operator, sender: message.sender, - content: message.attachment?.selectedOption ?? "", + content: message.content, attachment: message.attachment, downloads: message.downloads ), - status: nil + showsImage: false, + imageUrl: message.operator?.pictureUrl ) ) section.replaceItem(at: index, with: item) diff --git a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift index 22378cf87..c995a8ce1 100644 --- a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift @@ -820,7 +820,6 @@ extension ChatViewModel { // MARK: Message sending retry extension ChatViewModel { - // TODO: - This will be covered with unit tests in next PR private func retryMessageSending(_ outgoingMessage: OutgoingMessage) { removeMessage( outgoingMessage, @@ -839,8 +838,6 @@ extension ChatViewModel { if !self.hasReceivedMessage(messageId: message.id) { self.registerReceivedMessage(messageId: message.id) - self.updateSelectedOption(with: outgoingMessage) - self.replace( outgoingMessage, uploads: [], @@ -849,6 +846,8 @@ extension ChatViewModel { ) self.action?(.scrollToBottom(animated: true)) } + + self.updateSelectedOption(with: outgoingMessage) case .failure: self.markMessageAsFailed( outgoingMessage, diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModel.DividedChatItemsForUnreadCountTests.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModel.DividedChatItemsForUnreadCountTests.swift index 64063d137..863e3eefd 100644 --- a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModel.DividedChatItemsForUnreadCountTests.swift +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModel.DividedChatItemsForUnreadCountTests.swift @@ -1,7 +1,7 @@ @testable import GliaWidgets import XCTest -class SecureConversationsTranscriptModelDividerTests { +class SecureConversationsTranscriptModelDividerTests: XCTestCase { // Since ChatItem does not conform to Equatable, // one of the ways to evaluate if it is the exact // item is by doing identity check. diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+GVA.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+GVA.swift index 397df4b4d..c181711f0 100644 --- a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+GVA.swift +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+GVA.swift @@ -159,6 +159,7 @@ extension SecureConversationsTranscriptModelTests { environment: modelEnv, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) viewModel.action = { action in @@ -203,6 +204,7 @@ private extension SecureConversationsTranscriptModelTests { environment: modelEnv, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) } diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+MessageRetry.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+MessageRetry.swift new file mode 100644 index 000000000..d4d8fd140 --- /dev/null +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+MessageRetry.swift @@ -0,0 +1,153 @@ +@testable import GliaWidgets +import XCTest + +extension SecureConversationsTranscriptModelTests { + func testSendMessageRetrySuccess() { + let outgoingMessage = OutgoingMessage.mock() + var calls: [Call] = [] + let viewModel = createViewModel() + + viewModel.action = { action in + switch action { + case let .deleteRows(rows, section, animated): + calls.append(.deleteRows(rows, section, animated)) + + case let .appendRows(index, section, animated): + calls.append(.appendRows(index, section, animated)) + + case let .scrollToBottom(animated): + calls.append(.scrollToBottom(animated)) + + default: + XCTFail("unexpected action was called") + } + } + + let expectedCalls: [Call] = [ + .deleteRows([1], 1, true), + .appendRows(1, 1, true), + .scrollToBottom(true) + ] + + /* + 1st - successfully sent visitor message + 2nd - failed outgoing visitor message + 3rd - successfully sent visitor message + */ + viewModel.pendingSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + viewModel.pendingSection.append(.init(kind: .outgoingMessage(outgoingMessage, error: "Failed"))) + viewModel.pendingSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + + viewModel.event(.retryMessageTapped(outgoingMessage)) + + XCTAssertEqual(calls, expectedCalls) + XCTAssertEqual(viewModel.pendingSection.itemCount, 3) + + // Check if failed outgoing message was removed and added as last one + switch viewModel.pendingSection.items.last?.kind { + case let .outgoingMessage(message, error): + XCTAssertEqual(message, outgoingMessage) + XCTAssertNil(error) + default: + XCTFail("message kind should be `outgoingMessage`") + } + } + + func testSendMessageRetryFailure() { + let outgoingMessage = OutgoingMessage.mock() + var calls: [Call] = [] + let viewModel = createViewModel() + + viewModel.action = { action in + switch action { + case let .deleteRows(rows, section, animated): + calls.append(.deleteRows(rows, section, animated)) + + case let .appendRows(index, section, animated): + calls.append(.appendRows(index, section, animated)) + + case let .scrollToBottom(animated): + calls.append(.scrollToBottom(animated)) + + case let .refreshRows(rows, section, animated): + calls.append(.refresh(rows, section, animated)) + + default: + XCTFail("unexpected action was called") + } + } + + viewModel.environment.sendSecureMessagePayload = { _, _, completion in + completion(.failure(GliaError.internalError)) + return .mock + } + + let expectedCalls: [Call] = [ + .deleteRows([1], 1, true), + .appendRows(1, 1, true), + .scrollToBottom(true), + .refresh([2], 1, false) + ] + + /* + 1st - successfully sent visitor message + 2nd - failed outgoing visitor message + 3rd - successfully sent visitor message + */ + viewModel.pendingSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + viewModel.pendingSection.append(.init(kind: .outgoingMessage(outgoingMessage, error: "Failed"))) + viewModel.pendingSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + + viewModel.event(.retryMessageTapped(outgoingMessage)) + + XCTAssertEqual(calls, expectedCalls) + XCTAssertEqual(viewModel.pendingSection.itemCount, 3) + + // Check if failed outgoing message was removed and added as last one + switch viewModel.pendingSection.items.last?.kind { + case let .outgoingMessage(message, error): + XCTAssertEqual(message, outgoingMessage) + XCTAssertEqual(error, "Failed") + default: + XCTFail("message kind should be `outgoingMessage`") + } + } +} + +private extension SecureConversationsTranscriptModelTests { + enum Call: Equatable { + case deleteRows([Int], Int, Bool) + case appendRows(Int, Int, Bool) + case refresh([Int], Int, Bool) + case scrollToBottom(Bool) + } + + func createViewModel() -> TranscriptModel { + var modelEnv = TranscriptModel.Environment.failing + var logger = CoreSdkClient.Logger.failing + logger.prefixedClosure = { _ in logger } + logger.infoClosure = { _, _, _, _ in } + logger.warningClosure = { _, _, _, _ in } + modelEnv.log = logger + modelEnv.fileManager = .mock + modelEnv.createFileUploadListModel = { _ in .mock() } + modelEnv.listQueues = { callback in callback([], nil) } + modelEnv.uiApplication.canOpenURL = { _ in true } + modelEnv.maximumUploads = { 2 } + modelEnv.sendSecureMessagePayload = { _, _, _ in .mock } + let availabilityEnv = SecureConversations.Availability.Environment( + listQueues: modelEnv.listQueues, + isAuthenticated: { true }, + log: logger + ) + + return TranscriptModel( + isCustomCardSupported: false, + environment: modelEnv, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + failedToDeliverStatusText: "Failed", + interactor: .failing + ) + } +} diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+ResponseCard.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+ResponseCard.swift new file mode 100644 index 000000000..8bfb14da7 --- /dev/null +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+ResponseCard.swift @@ -0,0 +1,61 @@ +@testable import GliaWidgets +import XCTest + +extension SecureConversationsTranscriptModelTests { + func test_singleChoiceResponseCardActionIsNotSupported() throws { + let viewModel = createViewModel() + viewModel.delegate = { _ in + XCTFail("Single choice response card actions should not be handled") + } + + let option = try ChatChoiceCardOption.mock() + + viewModel.event(.choiceOptionSelected(option, "messageId")) + } + + func test_customResponseCardActionIsNotSupported() throws { + let viewModel = createViewModel() + viewModel.delegate = { _ in + XCTFail("Custom response card actions should not be handled") + } + + let option = HtmlMetadata.Option(text: "text", value: "value") + let messageId = MessageRenderer.Message.Identifier(rawValue: "messageId") + viewModel.event( + .customCardOptionSelected( + option: option, + messageId: messageId + ) + ) + } +} + +private extension SecureConversationsTranscriptModelTests { + func createViewModel() -> TranscriptModel { + var modelEnv = TranscriptModel.Environment.failing + var logger = CoreSdkClient.Logger.failing + logger.prefixedClosure = { _ in logger } + logger.infoClosure = { _, _, _, _ in } + logger.warningClosure = { _, _, _, _ in } + modelEnv.log = logger + modelEnv.fileManager = .mock + modelEnv.createFileUploadListModel = { _ in .mock() } + modelEnv.listQueues = { callback in callback([], nil) } + modelEnv.uiApplication.canOpenURL = { _ in true } + modelEnv.maximumUploads = { 2 } + let availabilityEnv = SecureConversations.Availability.Environment( + listQueues: modelEnv.listQueues, + isAuthenticated: { true }, + log: logger + ) + + return TranscriptModel( + isCustomCardSupported: false, + environment: modelEnv, + availability: .init(environment: availabilityEnv), + deliveredStatusText: "", + failedToDeliverStatusText: "", + interactor: .failing + ) + } +} diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+URLs.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+URLs.swift index f2226e9f3..1667c6809 100644 --- a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+URLs.swift +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests+URLs.swift @@ -98,6 +98,7 @@ private extension SecureConversationsTranscriptModelTests { environment: modelEnv, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) } diff --git a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift index fc368247b..3b1718c06 100644 --- a/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift +++ b/GliaWidgetsTests/SecureConversations/ChatTranscript/TranscriptModelTests.swift @@ -27,7 +27,8 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { availability: .init( environment: availabilityEnv ), - deliveredStatusText: "", + deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -56,6 +57,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -89,6 +91,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -132,6 +135,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) viewModel.start() @@ -163,6 +167,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) viewModel.start() @@ -209,6 +214,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -249,6 +255,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -285,6 +292,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -327,6 +335,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -365,6 +374,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -406,6 +416,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) @@ -456,6 +467,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: interactor ) @@ -520,6 +532,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: interactor ) @@ -573,6 +586,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: modelEnvironment, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) XCTAssertFalse(model.isSecureConversationsAvailable) @@ -601,6 +615,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: modelEnvironment, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) XCTAssertFalse(model.isSecureConversationsAvailable) @@ -627,6 +642,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: modelEnvironment, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) XCTAssertFalse(model.isSecureConversationsAvailable) @@ -655,6 +671,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: modelEnvironment, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) XCTAssertFalse(model.isSecureConversationsAvailable) @@ -683,6 +700,7 @@ final class SecureConversationsTranscriptModelTests: XCTestCase { environment: modelEnvironment, availability: .init(environment: availabilityEnv), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing ) var actions: [TranscriptModel.Action] = [] diff --git a/GliaWidgetsTests/SecureConversations/SecureConversations.ChatWithTranscriptModel/SecureConversations.ChatWithTranscriptModelTests.swift b/GliaWidgetsTests/SecureConversations/SecureConversations.ChatWithTranscriptModel/SecureConversations.ChatWithTranscriptModelTests.swift new file mode 100644 index 000000000..5d89e559c --- /dev/null +++ b/GliaWidgetsTests/SecureConversations/SecureConversations.ChatWithTranscriptModel/SecureConversations.ChatWithTranscriptModelTests.swift @@ -0,0 +1,73 @@ +@testable import GliaWidgets +import XCTest + +final class SecureConversationsChatWithTranscriptModelTests: XCTestCase { + typealias Model = SecureConversations.ChatWithTranscriptModel + + func testMarkMessageAsFailed() { + let itemIndex = 1 + let sectionIndex = 3 + let errorMessage = "Failed" + let section = Section(sectionIndex) + let outgoingMessage = OutgoingMessage(payload: .mock()) + let item = ChatItem(with: outgoingMessage) + + section.append(ChatItem(kind: .operatorMessage(.mock(), showsImage: false, imageUrl: nil))) + section.append(item) + section.append(ChatItem(kind: .operatorMessage(.mock(), showsImage: false, imageUrl: nil))) + + Model.markMessageAsFailed( + outgoingMessage, + in: section, + message: errorMessage + ) { action in + switch action { + case let .refreshRows(rows, section, _): + XCTAssertEqual(rows, [itemIndex]) + XCTAssertEqual(section, sectionIndex) + default: + XCTFail("action should be `refreshRows`") + } + } + + switch section.items[itemIndex].kind { + case let .outgoingMessage(message, error): + XCTAssertEqual(message.payload.messageId, message.payload.messageId) + XCTAssertEqual(error, errorMessage) + default: + XCTFail("Message kind should be `outgoingMessage`") + } + } + + func testRemoveMessage() { + let itemIndex = 1 + let sectionIndex = 3 + let section = Section(sectionIndex) + let outgoingMessage = OutgoingMessage(payload: .mock()) + let item = ChatItem(with: outgoingMessage) + + section.append(ChatItem(kind: .operatorMessage(.mock(), showsImage: false, imageUrl: nil))) + section.append(item) + section.append(ChatItem(kind: .operatorMessage(.mock(), showsImage: false, imageUrl: nil))) + + XCTAssertEqual(section.itemCount, 3) + + Model.removeMessage( + outgoingMessage, + in: section + ) { action in + switch action { + case let .deleteRows(rows, section, _): + XCTAssertEqual(rows, [itemIndex]) + XCTAssertEqual(section, sectionIndex) + default: + XCTFail("action should be `deleteRows`") + } + } + + let contains = section.items.contains(where: { $0.kind == item.kind }) + + XCTAssertEqual(contains, false) + XCTAssertEqual(section.itemCount, 2) + } +} diff --git a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+MessageRetry.swift b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+MessageRetry.swift new file mode 100644 index 000000000..cda496da7 --- /dev/null +++ b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+MessageRetry.swift @@ -0,0 +1,142 @@ +@testable import GliaWidgets +import XCTest + +extension ChatViewModelTests { + func testSendMessageRetrySuccess() { + let outgoingMessage = OutgoingMessage.mock() + var calls: [Call] = [] + var interactorEnv = Interactor.Environment.mock + interactorEnv.coreSdk.sendMessageWithMessagePayload = { _, completion in + completion(.success(.mock(id: outgoingMessage.payload.messageId.rawValue))) + } + let interactorMock = Interactor.mock(environment: interactorEnv) + let deliveredStatusText = "Delivered" + viewModel = .mock( + interactor: interactorMock, + deliveredStatusText: deliveredStatusText + ) + + viewModel.action = { action in + switch action { + case let .deleteRows(rows, section, animated): + calls.append(.deleteRows(rows, section, animated)) + + case let .appendRows(index, section, animated): + calls.append(.appendRows(index, section, animated)) + + case let .scrollToBottom(animated): + calls.append(.scrollToBottom(animated)) + + case let .refreshRows(rows, section, animated): + calls.append(.refreshRows(rows, section, animated)) + + default: + XCTFail("unexpected action was called") + } + } + + let expectedCalls: [Call] = [ + .deleteRows([1], 3, true), + .appendRows(1, 3, true), + .scrollToBottom(true), + .refreshRows([2], 3, false), + .scrollToBottom(true) + ] + + /* + 1st - successfully sent visitor message + 2nd - failed outgoing visitor message + 3rd - successfully sent visitor message + */ + viewModel.messagesSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + viewModel.messagesSection.append(.init(kind: .outgoingMessage(outgoingMessage, error: "Failed"))) + viewModel.messagesSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + + viewModel.event(.retryMessageTapped(outgoingMessage)) + + XCTAssertEqual(calls, expectedCalls) + XCTAssertEqual(viewModel.messagesSection.itemCount, 3) + + // Check if failed outgoing message was removed and added as last one + switch viewModel.messagesSection.items.last?.kind { + case let .visitorMessage(message, status): + XCTAssertEqual(message.id, outgoingMessage.payload.messageId.rawValue) + XCTAssertEqual(status, deliveredStatusText) + default: + XCTFail("message kind should be `visitorMessage`") + } + } + + func testSendMessageRetryFailure() { + let outgoingMessage = OutgoingMessage.mock() + var calls: [Call] = [] + var interactorEnv = Interactor.Environment.mock + interactorEnv.coreSdk.sendMessageWithMessagePayload = { _, completion in + completion(.failure(.mock())) + } + let interactorMock = Interactor.mock(environment: interactorEnv) + let failedToDeliverStatusText = "Failed" + viewModel = .mock( + interactor: interactorMock, + failedToDeliverStatusText: failedToDeliverStatusText + ) + + viewModel.action = { action in + switch action { + case let .deleteRows(rows, section, animated): + calls.append(.deleteRows(rows, section, animated)) + + case let .appendRows(index, section, animated): + calls.append(.appendRows(index, section, animated)) + + case let .scrollToBottom(animated): + calls.append(.scrollToBottom(animated)) + + case let .refreshRows(rows, section, animated): + calls.append(.refreshRows(rows, section, animated)) + + default: + XCTFail("unexpected action was called") + } + } + + let expectedCalls: [Call] = [ + .deleteRows([1], 3, true), + .appendRows(1, 3, true), + .scrollToBottom(true), + .refreshRows([2], 3, false) + ] + + /* + 1st - successfully sent visitor message + 2nd - failed outgoing visitor message + 3rd - successfully sent visitor message + */ + viewModel.messagesSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + viewModel.messagesSection.append(.init(kind: .outgoingMessage(outgoingMessage, error: "Failed"))) + viewModel.messagesSection.append(.init(kind: .visitorMessage(ChatMessage.mock(), status: nil))) + + viewModel.event(.retryMessageTapped(outgoingMessage)) + + XCTAssertEqual(calls, expectedCalls) + XCTAssertEqual(viewModel.messagesSection.itemCount, 3) + + // Check if failed outgoing message was removed and added as last one + switch viewModel.messagesSection.items.last?.kind { + case let .outgoingMessage(message, error): + XCTAssertEqual(message, outgoingMessage) + XCTAssertEqual(error, failedToDeliverStatusText) + default: + XCTFail("message kind should be `outgoingMessage`") + } + } +} + +private extension ChatViewModelTests { + enum Call: Equatable { + case deleteRows([Int], Int, Bool) + case appendRows(Int, Int, Bool) + case refreshRows([Int], Int, Bool) + case scrollToBottom(Bool) + } +} diff --git a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift index bc8d80a78..a16e58e85 100644 --- a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift +++ b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift @@ -465,6 +465,7 @@ class ChatViewModelTests: XCTestCase { environment: availabilityEnv ), deliveredStatusText: "", + failedToDeliverStatusText: "", interactor: .failing )