Skip to content

Commit

Permalink
Display Live Observation alert before normal engagement
Browse files Browse the repository at this point in the history
This PR displays Live Observation confirmation alert before normal engagement.
This alert can't be skipped and needs visitor's manual confirmation to
enqueue.

MOB-2678
  • Loading branch information
rasmustautsglia authored and github-review-helper committed Oct 11, 2023
1 parent 5bde999 commit 032f32d
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 50 deletions.
22 changes: 18 additions & 4 deletions GliaWidgets.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,8 @@
C0175A282A67D470001FACDE /* GvaPersistentButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0175A272A67D470001FACDE /* GvaPersistentButtonStyle.swift */; };
C0175A2A2A67D499001FACDE /* GvaStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0175A292A67D499001FACDE /* GvaStyle.swift */; };
C0175A2C2A67E2E9001FACDE /* Theme+Gva.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0175A2B2A67E2E9001FACDE /* Theme+Gva.swift */; };
C02248A72AD53DDA00CC4930 /* LiveObservationConfirmation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C02248A62AD53DDA00CC4930 /* LiveObservationConfirmation.swift */; };
C02248AA2AD53E6100CC4930 /* LiveObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C02248A92AD53E6100CC4930 /* LiveObservation.swift */; };
C03A8047292BA76D00DDECA6 /* ChatViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C03A8046292BA76D00DDECA6 /* ChatViewControllerTests.swift */; };
C03A8049292BC8DB00DDECA6 /* CallViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C03A8048292BC8DB00DDECA6 /* CallViewControllerTests.swift */; };
C05AB01C295F416700AA381F /* VisitorCodeCloseButtonProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05AB01B295F416700AA381F /* VisitorCodeCloseButtonProperties.swift */; };
Expand All @@ -599,10 +601,10 @@
C06A7586296ECC57006B69A2 /* VisitorCodeStyle.Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06A7585296ECC57006B69A2 /* VisitorCodeStyle.Accessibility.swift */; };
C06A7588296ECD75006B69A2 /* Theme+VisitorCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06A7587296ECD75006B69A2 /* Theme+VisitorCode.swift */; };
C07F62462ABC322B003EFC97 /* OrientationManager.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F62452ABC322B003EFC97 /* OrientationManager.Mock.swift */; };
C07F62772AC1BA2B003EFC97 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */; };
C07F62792AC2D2E8003EFC97 /* BackgroundSwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F62782AC2D2E8003EFC97 /* BackgroundSwiftUI.swift */; };
C07F627D2AC2F31F003EFC97 /* ScreenSharingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F627C2AC2F31F003EFC97 /* ScreenSharingViewModel.swift */; };
C07F62812AC3057C003EFC97 /* ScreenSharingViewModel.mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F62802AC3057C003EFC97 /* ScreenSharingViewModel.mock.swift */; };
C07F62772AC1BA2B003EFC97 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */; };
C07F62832AC33BB9003EFC97 /* UIView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07F62822AC33BB9003EFC97 /* UIView+Extensions.swift */; };
C07FA04029AF542A00E9FB7F /* ScreenSharingViewStyle+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E0B298AECBA00D65842 /* ScreenSharingViewStyle+Mock.swift */; };
C07FA04B29AF83B900E9FB7F /* ActionButton.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */; };
Expand Down Expand Up @@ -1329,6 +1331,8 @@
C0175A272A67D470001FACDE /* GvaPersistentButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaPersistentButtonStyle.swift; sourceTree = "<group>"; };
C0175A292A67D499001FACDE /* GvaStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaStyle.swift; sourceTree = "<group>"; };
C0175A2B2A67E2E9001FACDE /* Theme+Gva.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Gva.swift"; sourceTree = "<group>"; };
C02248A62AD53DDA00CC4930 /* LiveObservationConfirmation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveObservationConfirmation.swift; sourceTree = "<group>"; };
C02248A92AD53E6100CC4930 /* LiveObservation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveObservation.swift; sourceTree = "<group>"; };
C03A8046292BA76D00DDECA6 /* ChatViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewControllerTests.swift; sourceTree = "<group>"; };
C03A8048292BC8DB00DDECA6 /* CallViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallViewControllerTests.swift; sourceTree = "<group>"; };
C05AB016295DA9FC00AA381F /* AlertViewController+VisitorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlertViewController+VisitorCode.swift"; sourceTree = "<group>"; };
Expand All @@ -1342,13 +1346,11 @@
C06A7585296ECC57006B69A2 /* VisitorCodeStyle.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorCodeStyle.Accessibility.swift; sourceTree = "<group>"; };
C06A7587296ECD75006B69A2 /* Theme+VisitorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+VisitorCode.swift"; sourceTree = "<group>"; };
C07F62452ABC322B003EFC97 /* OrientationManager.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationManager.Mock.swift; sourceTree = "<group>"; };
C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = "<group>"; };
C07F62782AC2D2E8003EFC97 /* BackgroundSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSwiftUI.swift; sourceTree = "<group>"; };
C07F627C2AC2F31F003EFC97 /* ScreenSharingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewModel.swift; sourceTree = "<group>"; };
C07F62802AC3057C003EFC97 /* ScreenSharingViewModel.mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewModel.mock.swift; sourceTree = "<group>"; };
C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = "<group>"; };
C07F62822AC33BB9003EFC97 /* UIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = "<group>"; };
C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingView.Mock.swift; sourceTree = "<group>"; };
C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewController.Mock.swift; sourceTree = "<group>"; };
C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.Mock.swift; sourceTree = "<group>"; };
C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenShareViewControllerVoiceOverTests.swift; sourceTree = "<group>"; };
C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCallViewControllerVoiceOverTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2059,6 +2061,7 @@
1A60AFC12566857200E53F53 /* Sources */ = {
isa = PBXGroup;
children = (
C02248A82AD53DDF00CC4930 /* LiveObservation */,
84D5B95E2A14DEFD00807F92 /* QuickLookBased */,
C05E3EDC29C99DEE0013BC81 /* ProximityManager */,
C4794E6E270673FC00F989F7 /* Animation */,
Expand Down Expand Up @@ -3513,6 +3516,15 @@
path = GVA;
sourceTree = "<group>";
};
C02248A82AD53DDF00CC4930 /* LiveObservation */ = {
isa = PBXGroup;
children = (
C02248A92AD53E6100CC4930 /* LiveObservation.swift */,
C02248A62AD53DDA00CC4930 /* LiveObservationConfirmation.swift */,
);
path = LiveObservation;
sourceTree = "<group>";
};
C05E3EDC29C99DEE0013BC81 /* ProximityManager */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4471,6 +4483,7 @@
84D2293028C61FF300F64FE7 /* WKNavigationPolicyProvider.Mock.swift in Sources */,
1A0C144425B868FC00B00695 /* CallCoordinator.swift in Sources */,
8491AF022A6FBBBA00CC3E72 /* GvaGalleryListView.swift in Sources */,
C02248A72AD53DDA00CC4930 /* LiveObservationConfirmation.swift in Sources */,
7594098C298D38C2008B173A /* CallVisualizer+Environment.swift in Sources */,
1A1E309B25F8E1F700850E68 /* DataStorage.swift in Sources */,
AF6AB34D298A9F2500003645 /* SecureConversations.FileUploadListViewModel.swift in Sources */,
Expand Down Expand Up @@ -4743,6 +4756,7 @@
AF3D520F2983BC5600AD8E69 /* FileUploader.Environment.Mock.swift in Sources */,
C43D7A1125FF92680064B1DA /* ChoiceCardStyle.swift in Sources */,
9A186A4127F605B90055886D /* HeaderButtonStyle.Accessibility.swift in Sources */,
C02248AA2AD53E6100CC4930 /* LiveObservation.swift in Sources */,
9AB196D827C3E27300FD60AB /* ChatViewModel.Environment.Mock.swift in Sources */,
3100EEFF293F7E0900D57F71 /* Theme+SecureConversationsWelcome.swift in Sources */,
9A8130BF27D7AEF700220BBD /* FileUpload.Mock.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ import Foundation
protocol CommonEngagementModel: AnyObject {
var engagementAction: EngagementViewModel.ActionCallback? { get set }
var engagementDelegate: EngagementViewModel.DelegateCallback? { get set }
var hasViewAppeared: Bool { get }
func event(_ event: EngagementViewModel.Event)
func setViewAppeared()
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ extension SecureConversations {

var action: ActionCallback?
var delegate: DelegateCallback?

var engagementAction: EngagementViewModel.ActionCallback?
var engagementDelegate: EngagementViewModel.DelegateCallback?

Expand All @@ -43,7 +42,7 @@ extension SecureConversations {

private let downloader: FileDownloader
let fileUploadListModel: SecureConversations.FileUploadListViewModel

private (set) var hasViewAppeared: Bool
private (set) var messageText = "" {
didSet {
validateMessage()
Expand Down Expand Up @@ -117,7 +116,7 @@ extension SecureConversations {
self.deliveredStatusText = deliveredStatusText
self.interactor = interactor
self.alertConfiguration = alertConfiguration

self.hasViewAppeared = false
let uploader = FileUploader(
maximumUploads: Self.maximumUploads,
environment: .init(
Expand Down Expand Up @@ -746,3 +745,10 @@ extension SecureConversations.TranscriptModel {

}
}

// MARK: View Appeared
extension SecureConversations.TranscriptModel {
func setViewAppeared() {
hasViewAppeared = true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class EngagementCoordinator: SubFlowCoordinator, FlowCoordinator {

// swiftlint:disable function_body_length
func start() {

switch engagementKind {
case .none:
break
Expand All @@ -59,6 +60,7 @@ class EngagementCoordinator: SubFlowCoordinator, FlowCoordinator {
showsCallBubble: false
)
engagement = .chat(chatViewController)
interactor.state = .enqueueing(.text)
navigationPresenter.setViewControllers(
[chatViewController],
animated: false
Expand All @@ -81,22 +83,23 @@ class EngagementCoordinator: SubFlowCoordinator, FlowCoordinator {
call.kind.addObserver(self) { [weak self] _, _ in
self?.engagementKind = EngagementKind(with: call.kind.value)
}
let chatViewController = startChat(
withAction: .none,
showsCallBubble: true
)

let callViewController = startCall(
call,
withAction: .engagement(mediaType: mediaType)
)
interactor.state = .enqueueing(mediaType)
let chatViewController = startChat(
withAction: .none,
showsCallBubble: true
)

engagement = .call(
callViewController,
chatViewController,
.none,
call
)

navigationPresenter.setViewControllers(
[callViewController],
animated: false
Expand Down
4 changes: 1 addition & 3 deletions GliaWidgets/Sources/Interactor/Interactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

enum InteractorState {
case none
case enqueueing
case enqueueing(CoreSdkClient.MediaType)
case enqueued(CoreSdkClient.QueueTicket)
case engaged(CoreSdkClient.Operator?)
case ended(EndEngagementReason)
Expand Down Expand Up @@ -140,8 +140,6 @@ extension Interactor {
success: @escaping () -> Void,
failure: @escaping (CoreSdkClient.SalemoveError) -> Void
) {
state = .enqueueing

let options = mediaType == .audio || mediaType == .video
? CoreSdkClient.EngagementOptions(mediaDirection: .twoWay)
: nil
Expand Down
3 changes: 3 additions & 0 deletions GliaWidgets/Sources/LiveObservation/LiveObservation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Foundation

struct LiveObservation {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Foundation

extension LiveObservation {
struct Confirmation {
let conf: ConfirmationAlertConfiguration
let accepted: () -> Void
let declined: () -> Void
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ extension ChatViewController {

fileUploadListModel.environment.uploader.uploads.append(fileUploadWithError)
fileUploadWithError.state.value = .error(FileUpload.Error.fileTooBig)

chatViewModel.interactor.state = .enqueueing(.text)
chatViewModel.action?(.sendButtonHidden(false))
chatViewModel.action?(.updateUnreadMessageIndicator(itemCount: 5))
chatViewModel.action?(.setChoiceCardInputModeEnabled(false))
Expand Down
30 changes: 30 additions & 0 deletions GliaWidgets/Sources/ViewController/EngagementViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import UIKit
class EngagementViewController: UIViewController, AlertPresenter, MediaUpgradePresenter, ScreenShareOfferPresenter {
let viewFactory: ViewFactory
private var viewModel: CommonEngagementModel
private var pendingLiveObservationConfirmation: LiveObservation.Confirmation?

init(viewModel: CommonEngagementModel, viewFactory: ViewFactory) {
self.viewModel = viewModel
Expand All @@ -27,6 +28,11 @@ class EngagementViewController: UIViewController, AlertPresenter, MediaUpgradePr
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
viewModel.event(.viewDidAppear)
viewModel.setViewAppeared()
if let alertConfig = pendingLiveObservationConfirmation {
showLiveObservationConfirmationAlert(with: alertConfig)
pendingLiveObservationConfirmation = nil
}
}

override func viewDidDisappear(_ animated: Bool) {
Expand Down Expand Up @@ -63,6 +69,8 @@ class EngagementViewController: UIViewController, AlertPresenter, MediaUpgradePr
view?.header.showEndButton()
case .showEndScreenShareButton:
view?.header.showEndScreenSharingButton()
case let .showLiveObservationConfirmation(configuration):
self.showLiveObservationConfirmation(with: configuration)
}
}
}
Expand All @@ -71,4 +79,26 @@ class EngagementViewController: UIViewController, AlertPresenter, MediaUpgradePr
self.viewModel = engagementModel
bind(engagementViewModel: engagementModel)
}

private func showLiveObservationConfirmation(
with config: LiveObservation.Confirmation
) {
switch viewModel.hasViewAppeared {
case true: showLiveObservationConfirmationAlert(with: config)
case false: pendingLiveObservationConfirmation = config
}
}

private func showLiveObservationConfirmationAlert(with config: LiveObservation.Confirmation) {
let alert = AlertViewController(
kind: .liveObservationConfirmation(
config.conf,
accepted: config.accepted,
declined: config.declined
),
viewFactory: self.viewFactory
)

replacePresentedOfferIfPossible(with: alert)
}
}
5 changes: 2 additions & 3 deletions GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,8 @@ class CallViewModel: EngagementViewModel, ViewModel {
update(for: interactor.state)

switch startWith {
case .engagement(let mediaType):
enqueue(mediaType: mediaType)

case .engagement:
break
case .call(offer: let offer, answer: let answer):
call.upgrade(to: offer)
showConnecting()
Expand Down
18 changes: 2 additions & 16 deletions GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,18 +168,7 @@ class ChatViewModel: EngagementViewModel {

override func start() {
super.start()

loadHistory { [weak self] history in
guard let self = self else { return }
// We only proceed to considering enqueue flow if `startAction` is about starting of engagement.
guard case .startEngagement = self.startAction else { return }
// We enqueue eagerly in case if this is the first engagement for visitor (by evaluating previous chat history)
// or in case if engagement has been restored.

if history.isEmpty || self.environment.getCurrentEngagement() != nil {
self.enqueue(mediaType: .text)
}
}
loadHistory()
}

override func update(for state: InteractorState) {
Expand All @@ -198,7 +187,6 @@ class ChatViewModel: EngagementViewModel {

action?(.queue)
action?(.scrollToBottom(animated: true))

case .engaged(let engagedOperator):
let name = engagedOperator?.firstName
let pictureUrl = engagedOperator?.picture?.url
Expand Down Expand Up @@ -247,7 +235,6 @@ class ChatViewModel: EngagementViewModel {
}
}
}

default:
break
}
Expand Down Expand Up @@ -378,7 +365,7 @@ extension ChatViewModel {
// MARK: History

extension ChatViewModel {
private func loadHistory(_ completion: @escaping ([ChatMessage]) -> Void) {
private func loadHistory() {
environment.fetchChatHistory { [weak self] result in
guard let self else { return }
let messages = (try? result.get()) ?? []
Expand All @@ -401,7 +388,6 @@ extension ChatViewModel {
self.historySection.set(items)
self.action?(.refreshSection(self.historySection.index))
self.action?(.scrollToBottom(animated: false))
completion(messages)
}
}
}
Expand Down
Loading

0 comments on commit 032f32d

Please sign in to comment.