From aad3a93e7a74464a18e2c8bee6e05f7da026358a Mon Sep 17 00:00:00 2001 From: Egor Egorov Date: Mon, 18 Sep 2023 20:24:13 +0300 Subject: [PATCH 01/40] Fix attachment button visibility Before attachment button was hidden when Response/Custom card was received. Now the button visibility behaviour is aligned with entry field blocking behaviour. If sending media is allowed in site setting, now the button is hidden only during enqueueing and transferring state. MOB-2636 --- GliaWidgets.xcodeproj/project.pbxproj | 4 + .../Chat/Entry/ChatMessageEntryView.swift | 3 - .../ViewModel/Chat/ChatViewModel.swift | 3 +- .../ChatViewModelTests+Transferring.swift | 79 +++++++++++++++++++ 4 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+Transferring.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 2b4208b5c..eb0cd4138 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -399,6 +399,7 @@ 8491AF602AA1EBB600CC3E72 /* TranscriptModelTests+URLs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491AF5F2AA1EBB600CC3E72 /* TranscriptModelTests+URLs.swift */; }; 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 */; }; 84A318A12869ECFC00CA1DE5 /* Unavailable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A318A02869ECFC00CA1DE5 /* Unavailable.swift */; }; 84CFB7732822700000167258 /* Theme.Button.Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CFB7722822700000167258 /* Theme.Button.Accessibility.swift */; }; 84D2292B28C61C8D00F64FE7 /* WKNavigationPolicyProvider.CustomResponseCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D2292A28C61C8D00F64FE7 /* WKNavigationPolicyProvider.CustomResponseCard.swift */; }; @@ -1126,6 +1127,7 @@ 8491AF5F2AA1EBB600CC3E72 /* TranscriptModelTests+URLs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TranscriptModelTests+URLs.swift"; sourceTree = ""; }; 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 = ""; }; 84A318A02869ECFC00CA1DE5 /* Unavailable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Unavailable.swift; sourceTree = ""; }; 84CFB7722822700000167258 /* Theme.Button.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.Button.Accessibility.swift; sourceTree = ""; }; 84D2292A28C61C8D00F64FE7 /* WKNavigationPolicyProvider.CustomResponseCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKNavigationPolicyProvider.CustomResponseCard.swift; sourceTree = ""; }; @@ -3141,6 +3143,7 @@ 7512A57927BF9FCD00319DF1 /* ChatViewModelTests.swift */, 84681A942A61844000DD7406 /* ChatViewModelTests+Gva.swift */, 8491AF642AAB281500CC3E72 /* ChatViewModelTests+CustomCard.swift */, + 8491AF662AB8707600CC3E72 /* ChatViewModelTests+Transferring.swift */, ); path = ChatViewModel; sourceTree = ""; @@ -4787,6 +4790,7 @@ AF29811229E42F3C0005BD55 /* AvailabilityTests.swift in Sources */, 9AE05CB32805C9D900871321 /* ChatViewModel.Environment.Failing.swift in Sources */, 7552DFB12A6FB7DF0093519B /* ChatMessageTests.swift in Sources */, + 8491AF672AB8707600CC3E72 /* ChatViewModelTests+Transferring.swift in Sources */, AFEF5C7429929A8D005C3D8D /* SecureConversations.FileUploadListViewModel.Environment.Failing.swift in Sources */, 9A3E1D9D27BA7741005634EB /* FoundationBased.Failing.swift in Sources */, 9A3E1D8427B67F1B005634EB /* Helper.swift in Sources */, diff --git a/GliaWidgets/Sources/View/Chat/Entry/ChatMessageEntryView.swift b/GliaWidgets/Sources/View/Chat/Entry/ChatMessageEntryView.swift index da7df154b..a7ed2c828 100644 --- a/GliaWidgets/Sources/View/Chat/Entry/ChatMessageEntryView.swift +++ b/GliaWidgets/Sources/View/Chat/Entry/ChatMessageEntryView.swift @@ -287,7 +287,6 @@ extension ChatMessageEntryView { enum MediaPickerButtonVisibility { enum ToggledBy { - case choiceCard case enagagementConnection(isConnected: Bool) case secureMessaging } @@ -300,8 +299,6 @@ extension MediaPickerButtonVisibility { switch self { case .disabled: return true - case .enabled(.choiceCard): - return true case let .enabled(.enagagementConnection(isConnected)): return !isConnected case .enabled(.secureMessaging): diff --git a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift index c1a20fbde..1c2ad4f60 100644 --- a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift @@ -58,7 +58,6 @@ class ChatViewModel: EngagementViewModel { guard environment.getCurrentEngagement() != nil else { return .enabled(.enagagementConnection(isConnected: false)) } - guard !isChoiceCardInputModeEnabled else { return .enabled(.choiceCard) } return .enabled(.enagagementConnection(isConnected: environment.getCurrentEngagement() != nil)) } @@ -313,6 +312,7 @@ extension ChatViewModel { extension ChatViewModel { private func onEngagementTransferring() { action?(.setMessageEntryEnabled(false)) + action?(.setAttachmentButtonVisibility(.disabled)) appendItem(.init(kind: .transferring), to: messagesSection, animated: true) action?(.scrollToBottom(animated: true)) endScreenSharing() @@ -320,6 +320,7 @@ extension ChatViewModel { private func onEngagementTransferred() { action?(.setMessageEntryEnabled(true)) + action?(.setAttachmentButtonVisibility(mediaPickerButtonVisibility)) let engagedOperator = interactor.engagedOperator action?(.setCallBubbleImage(imageUrl: engagedOperator?.picture?.url)) diff --git a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+Transferring.swift b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+Transferring.swift new file mode 100644 index 000000000..008911f97 --- /dev/null +++ b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests+Transferring.swift @@ -0,0 +1,79 @@ +@testable import GliaWidgets +import GliaCoreSDK +import XCTest + +extension ChatViewModelTests { + func test_mediaButtonVisibilityDuringTransferring() throws { + enum Call: Equatable { + enum Visibility { case enabled, disabled } + case updateVisibility(Visibility) + } + + var calls: [Call] = [] + + var interactorEnv = Interactor.Environment.failing + // To ensure `sendMessageWithMessagePayload` is not called in case of Postback Button + interactorEnv.coreSdk.sendMessageWithMessagePayload = { _, _ in + XCTFail("createSendMessagePayload should not be called") + } + interactorEnv.gcd.mainQueue.asyncIfNeeded = { $0() } + interactorEnv.coreSdk.queueForEngagement = { _, _ in } + interactorEnv.coreSdk.configureWithInteractor = { _ in } + let interactorMock = Interactor.mock(environment: interactorEnv) + interactorMock.isConfigurationPerformed = true + + var env = ChatViewModel.Environment.failing() + env.fileManager.fileExistsAtPath = { _ in true } + env.fileManager.createDirectoryAtUrlWithIntermediateDirectories = { _, _, _ in } + env.fileManager.urlsForDirectoryInDomainMask = { _, _ in [.mock] } + env.createFileUploadListModel = { _ in .mock() } + env.createSendMessagePayload = { _, _ in .mock() } + let site: CoreSdkClient.Site = try .mock( + allowedFileSenders: .init(operator: true, visitor: true) + ) + env.fetchSiteConfigurations = { completion in + completion(.success(site)) + } + env.getCurrentEngagement = { .mock() } + viewModel = .mock(interactor: interactorMock, environment: env) + + viewModel.action = { action in + switch action { + case let .setAttachmentButtonVisibility(visibility): + switch visibility { + case .enabled: + calls.append(.updateVisibility(.enabled)) + case .disabled: + calls.append(.updateVisibility(.disabled)) + } + default: + break + } + } + interactorMock.state = .engaged(nil) + XCTAssertEqual( + calls, + [.updateVisibility(.enabled)] + ) + + interactorMock.notify(.engagementTransferring) + XCTAssertEqual( + calls, + [ + .updateVisibility(.enabled), + .updateVisibility(.disabled) + ] + ) + + interactorMock.notify(.engagementTransferred(GliaCoreSDK.Operator.mock())) + + XCTAssertEqual( + calls, + [ + .updateVisibility(.enabled), + .updateVisibility(.disabled), + .updateVisibility(.enabled) + ] + ) + } +} From 3a9d3315d1bf80d24810ffc763cfdbd6f4101f9b Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Fri, 15 Sep 2023 15:57:23 +0300 Subject: [PATCH 02/40] Add landscape snapshot testing capability This PR adds a capability to snapshot test screens in landscape, both with regular and large font. MOB-2653 --- SnapshotTests/SnapshotTestCase.swift | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/SnapshotTests/SnapshotTestCase.swift b/SnapshotTests/SnapshotTestCase.swift index d6d46b3e2..92050d2e8 100644 --- a/SnapshotTests/SnapshotTestCase.swift +++ b/SnapshotTests/SnapshotTestCase.swift @@ -189,3 +189,34 @@ extension Snapshotting where Value == UIView, Format == UIImage { ) } } + +extension Snapshotting where Value == UIViewController, Format == UIImage { + private static var commonTraitCollection: [UITraitCollection] = [ + .init(layoutDirection: .leftToRight), + .init(userInterfaceIdiom: .phone), + .init(horizontalSizeClass: .regular), + .init(verticalSizeClass: .compact), + ] + + static var extra3LargeFontStrategyLandscape: Self { + let traits = UITraitCollection(traitsFrom: [ + .init(preferredContentSizeCategory: .accessibilityExtraExtraExtraLarge) + ] + commonTraitCollection) + let safeArea: UIEdgeInsets = .init(top: 0, left: 47, bottom: 21, right: 47) + let size: CGSize = .init(width: 844, height: 390) + let viewImageConfig: ViewImageConfig = .init(safeArea: safeArea, size: size, traits: traits) + + return Self.image(on: viewImageConfig) + } + + static var imageLandscape: Self { + let traits = UITraitCollection(traitsFrom: [ + .init(preferredContentSizeCategory: .medium), + ] + commonTraitCollection) + let safeArea: UIEdgeInsets = .init(top: 0, left: 47, bottom: 21, right: 47) + let size: CGSize = .init(width: 844, height: 390) + let viewImageConfig: ViewImageConfig = .init(safeArea: safeArea, size: size, traits: traits) + + return Self.image(on: viewImageConfig) + } +} From 02b2f5152766e777de38c4e06115bf260b507541 Mon Sep 17 00:00:00 2001 From: Igor Kravchenko Date: Mon, 18 Sep 2023 15:51:36 +0300 Subject: [PATCH 03/40] Discard delivered message by socket if it is from pending section In order to keep existing behaviour and avoid message duplication, messages placed in pending section once delivered via socket are discarded. MOB-2650 --- .../ViewModel/Chat/ChatViewModel.swift | 10 ++++++++ .../ChatViewModel/ChatViewModelTests.swift | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift index 1c2ad4f60..3f1495faf 100644 --- a/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Chat/ChatViewModel.swift @@ -664,6 +664,16 @@ extension ChatViewModel { return } + // Discard pending message delivered via socket to + // avoid message duplication. Currently pending messages + // stay in pending section whole session. + for pendingMessage in self.pendingSection.items { + if case let .outgoingMessage(outgoingPendingMessage) = pendingMessage.kind, + outgoingPendingMessage.payload.messageId.rawValue.uppercased() == message.id.uppercased() { + return + } + } + registerReceivedMessage(messageId: message.id) let receivedMessage = message diff --git a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift index 01df8c1e5..64593b0a2 100644 --- a/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift +++ b/GliaWidgetsTests/Sources/ChatViewModel/ChatViewModelTests.swift @@ -701,6 +701,31 @@ class ChatViewModelTests: XCTestCase { XCTAssertEqual(viewModel.receivedMessageIds, [expectedMessageId.uppercased()]) XCTAssertEqual(try XCTUnwrap(receivedMessage).id, expectedMessageId) } + + func test_messageContainedInPendingSectionDiscardsOneDeliveredViaSocket() throws { + var viewModelEnv = ChatViewModel.Environment.failing() + viewModelEnv.createFileUploadListModel = { _ in .mock() } + viewModelEnv.fileManager.urlsForDirectoryInDomainMask = { _, _ in [.mock] } + viewModelEnv.fileManager.createDirectoryAtUrlWithIntermediateDirectories = { _, _, _ in } + viewModelEnv.loadChatMessagesFromHistory = { true } + viewModelEnv.fetchSiteConfigurations = { _ in } + viewModelEnv.fetchChatHistory = { callback in + callback(.success([])) + } + let viewModel: ChatViewModel = .mock(environment: viewModelEnv) + viewModel.isViewLoaded = true + viewModel.start() + let messageIdSuffix = "1D_123" + + let outgoingMessage = OutgoingMessage(payload: .mock(messageIdSuffix: messageIdSuffix)) + viewModel.pendingSection.append( + .init(kind: .outgoingMessage(outgoingMessage)) + ) + + viewModel.interactorEvent(.receivedMessage(.mock(id: outgoingMessage.payload.messageId.rawValue))) + XCTAssertEqual(viewModel.messagesSection.items.count, 0) + XCTAssertEqual(viewModel.receivedMessageIds, []) + } } extension ChatChoiceCardOption { From 941b909f08b08fc9165c13e249a907bf6a9f36bf Mon Sep 17 00:00:00 2001 From: BitriseBot Date: Fri, 15 Sep 2023 08:55:47 +0000 Subject: [PATCH 04/40] Increment project version to 2.1.1 --- GliaWidgets.podspec | 2 +- GliaWidgets/Info.plist | 2 +- GliaWidgets/StaticValues.swift | 2 +- GliaWidgetsTests/Info.plist | 2 +- TestingApp/Info.plist | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GliaWidgets.podspec b/GliaWidgets.podspec index 02e348371..2deaec595 100644 --- a/GliaWidgets.podspec +++ b/GliaWidgets.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GliaWidgets' - s.version = '2.1.0' + s.version = '2.1.1' s.summary = 'The Glia iOS Widgets library' s.description = 'The Glia Widgets library allows to integrate easily a UI/UX for Glia\'s Digital Customer Service platform' s.homepage = 'https://github.com/salemove/ios-sdk-widgets' diff --git a/GliaWidgets/Info.plist b/GliaWidgets/Info.plist index 76778b66f..15f17b2d2 100644 --- a/GliaWidgets/Info.plist +++ b/GliaWidgets/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 2.1.0 + 2.1.1 CFBundleVersion $(CURRENT_PROJECT_VERSION) diff --git a/GliaWidgets/StaticValues.swift b/GliaWidgets/StaticValues.swift index 076753be1..7ed7e31de 100644 --- a/GliaWidgets/StaticValues.swift +++ b/GliaWidgets/StaticValues.swift @@ -6,5 +6,5 @@ final class StaticValues { /// version cannot be changed by integrators, so this ensures that our code will /// always have the correct version regardless of what our integrators do with /// our plist files. - static let sdkVersion = "2.1.0" + static let sdkVersion = "2.1.1" } diff --git a/GliaWidgetsTests/Info.plist b/GliaWidgetsTests/Info.plist index 735dbb5ea..d7938608e 100644 --- a/GliaWidgetsTests/Info.plist +++ b/GliaWidgetsTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 2.1.0 + 2.1.1 CFBundleVersion 1 diff --git a/TestingApp/Info.plist b/TestingApp/Info.plist index a20418bc5..2cdbe87b0 100644 --- a/TestingApp/Info.plist +++ b/TestingApp/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 2.1.0 + 2.1.1 CFBundleURLTypes From 3fc251a19884a46fcb1697d396de36f74b4c143f Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Wed, 13 Sep 2023 17:28:45 +0300 Subject: [PATCH 05/40] Convert ConfirmationView form UIKit to SwiftUI This PR is experimental, yet important first step towards transitioning to SwiftUI. ConfirmationView has been rewritten entirely in SwiftUI. The primary motivator for this PR was the frustrating nature of UIKit constraints. Key factors to keep in mind while reviewing: 1. Checkmark image has been made smaller, which was the request from the design team 2. UIFont does not translate 1:1 to SwiftUI Font, meaning the same font looks just a little big different now. But dynamic scaling works, and all our default fonts translate to expected outcome (font size, weight etc.) 3. Some approaches used in view layouts is due to the restrictions of SwiftUI 1.0 capabilities. Those can and will be upgraded in the future 4. The naming of Views, and Objects, as well as file locations in the directory are up for discussion. Everyone's input is much appreciated. 5. Prefix SwiftUI is used in lots of places due to a conflict with existing custom objects Button and Image 6. New HeaderSwiftUI view does not include all the possible configuration possibilities, as confirmations view's needs are not very demanding. So, that view can be upgraded in future. This PR also covers the ticket MOB-2488 which focuses on ADA-compliance in ConfigurationsView --- GliaWidgets.xcodeproj/project.pbxproj | 82 ++++- .../Public/Glia/Glia+StartEngagement.swift | 3 +- ...SecureConversations.ConfirmationView.swift | 283 +++++------------- ...ersations.ConfirmationViewController.swift | 53 ++-- ...eConversations.ConfirmationViewModel.swift | 116 +++---- ...heme+SecureConversationsConfirmation.swift | 2 +- .../SecureConversations.Coordinator.swift | 37 ++- ...gagementCoordinator.Environment.Mock.swift | 3 +- .../EngagementCoordinator.Environment.swift | 1 + .../EngagementCoordinator.swift | 4 +- .../FoundationBased.Interface.swift | 3 + .../FoundationBased.Live.swift | 4 +- .../FoundationBased.Mock.swift | 6 +- .../Glia.Environment.Interface.swift | 1 + .../Glia.Environment.Live.swift | 7 +- .../Glia.Environment.Mock.swift | 3 +- .../UIKitBased/UIKitBased.Interface.swift | 1 + .../Sources/UIKitBased/UIKitBased.Live.swift | 3 +- .../Sources/UIKitBased/UIKitBased.Mock.swift | 3 +- .../Sources/ViewFactory/ViewFactory.swift | 4 - .../Buttons/ActionButtonSwiftUI.swift | 65 ++++ .../Buttons/HeaderButtonSwiftUI.swift | 48 +++ .../Components/Header/HeaderSwiftUI.swift | 86 ++++++ .../SwiftUI/Extensions/Font+Extensions.swift | 7 + .../OrientationManager.Mock.swift | 19 ++ .../OrientationManager.swift | 38 +++ .../VideoCall/Mocks/HeaderStyle.Mock.swift | 5 +- .../RootCoordinator.Environment.Failing.swift | 3 +- .../FoundationBased.Failing.swift | 5 + .../Glia.Environment.Failing.swift | 3 +- ...ersations.ConfirmationViewModel.Mock.swift | 77 ++++- ...ersations.ConfirmationViewModelTests.swift | 86 +++--- GliaWidgetsTests/UIKitBased.Failing.swift | 4 + ...nfirmationScreenDynamicTypeFontTests.swift | 35 +-- ...sationsConfirmationScreenLayoutTests.swift | 37 +-- ...ConversationsConfirmationScreenTests.swift | 35 +-- 36 files changed, 700 insertions(+), 472 deletions(-) create mode 100644 GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift create mode 100644 GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift create mode 100644 GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift create mode 100644 GliaWidgets/SwiftUI/Extensions/Font+Extensions.swift create mode 100644 GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.Mock.swift create mode 100644 GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index eb0cd4138..837b163fd 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -590,11 +590,14 @@ C03A8049292BC8DB00DDECA6 /* CallViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C03A8048292BC8DB00DDECA6 /* CallViewControllerTests.swift */; }; C05AB01C295F416700AA381F /* VisitorCodeCloseButtonProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05AB01B295F416700AA381F /* VisitorCodeCloseButtonProperties.swift */; }; C05E3EDE29C99E070013BC81 /* ProximityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05E3EDD29C99E070013BC81 /* ProximityManager.swift */; }; + C06152D52AB1BC1300063BF8 /* Font+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06152D42AB1BC1300063BF8 /* Font+Extensions.swift */; }; + C06152DA2AB1BC4300063BF8 /* OrientationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06152D92AB1BC4300063BF8 /* OrientationManager.swift */; }; C06A757F296EC76B006B69A2 /* VisitorCodeStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06A757E296EC76B006B69A2 /* VisitorCodeStyle.swift */; }; C06A7582296EC856006B69A2 /* NumberSlotStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06A7581296EC856006B69A2 /* NumberSlotStyle.swift */; }; C06A7584296EC9DC006B69A2 /* NumberSlotStyle.Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C06A7583296EC9DC006B69A2 /* NumberSlotStyle.Accessibility.swift */; }; 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 */; }; C07FA04029AF542A00E9FB7F /* ScreenSharingViewStyle+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E0B298AECBA00D65842 /* ScreenSharingViewStyle+Mock.swift */; }; C07FA04329AF551D00E9FB7F /* ScreenSharingView.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */; }; C07FA04629AF560A00E9FB7F /* ScreenSharingViewController.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */; }; @@ -641,6 +644,9 @@ C0D2F08B29A4E95700803B47 /* ConnectView.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D2F08929A4E92D00803B47 /* ConnectView.Mock.swift */; }; C0D2F08C29A4EBA900803B47 /* VIdeoCallView.Environment.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D2F06F29A4DB5C00803B47 /* VIdeoCallView.Environment.Mock.swift */; }; C0D2F08F29A61A8D00803B47 /* VideoCallViewController.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D2F08D29A61A7800803B47 /* VideoCallViewController.Mock.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 */; }; C2B201AEDBE3A53369DF524F /* Pods_GliaWidgetsTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CCF7E6C5499635E67EF6A604 /* Pods_GliaWidgetsTests.framework */; }; C4119E06268F41D1004DFEFB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C4119E05268F41D1004DFEFB /* Main.storyboard */; }; C42463742673ABE10082C135 /* ScreenShareHandler.Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42463732673ABE10082C135 /* ScreenShareHandler.Interface.swift */; }; @@ -1322,11 +1328,14 @@ C05AB016295DA9FC00AA381F /* AlertViewController+VisitorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlertViewController+VisitorCode.swift"; sourceTree = ""; }; C05AB01B295F416700AA381F /* VisitorCodeCloseButtonProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorCodeCloseButtonProperties.swift; sourceTree = ""; }; C05E3EDD29C99E070013BC81 /* ProximityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProximityManager.swift; sourceTree = ""; }; + C06152D42AB1BC1300063BF8 /* Font+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Font+Extensions.swift"; sourceTree = ""; }; + C06152D92AB1BC4300063BF8 /* OrientationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationManager.swift; sourceTree = ""; }; C06A757E296EC76B006B69A2 /* VisitorCodeStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorCodeStyle.swift; sourceTree = ""; }; C06A7581296EC856006B69A2 /* NumberSlotStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberSlotStyle.swift; sourceTree = ""; }; C06A7583296EC9DC006B69A2 /* NumberSlotStyle.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberSlotStyle.Accessibility.swift; sourceTree = ""; }; C06A7585296ECC57006B69A2 /* VisitorCodeStyle.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorCodeStyle.Accessibility.swift; sourceTree = ""; }; C06A7587296ECD75006B69A2 /* Theme+VisitorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+VisitorCode.swift"; sourceTree = ""; }; + C07F62452ABC322B003EFC97 /* OrientationManager.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationManager.Mock.swift; sourceTree = ""; }; C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingView.Mock.swift; sourceTree = ""; }; C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewController.Mock.swift; sourceTree = ""; }; C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.Mock.swift; sourceTree = ""; }; @@ -1372,6 +1381,9 @@ C0D2F08629A4E8AE00803B47 /* CallButtonBar.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallButtonBar.Mock.swift; sourceTree = ""; }; C0D2F08929A4E92D00803B47 /* ConnectView.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectView.Mock.swift; sourceTree = ""; }; C0D2F08D29A61A7800803B47 /* VideoCallViewController.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallViewController.Mock.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 = ""; }; + C0E948082AB1D6AB00890026 /* HeaderSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderSwiftUI.swift; sourceTree = ""; }; C4119E05268F41D1004DFEFB /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; C42463732673ABE10082C135 /* ScreenShareHandler.Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenShareHandler.Interface.swift; sourceTree = ""; }; C43C12F82694B14900C37E1B /* GliaPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GliaPresenter.swift; sourceTree = ""; }; @@ -1644,6 +1656,7 @@ 1A205D5A25655CB1003AA3CD /* GliaWidgets */ = { isa = PBXGroup; children = ( + C06152D22AB1BBEF00063BF8 /* SwiftUI */, 313EBD53294310EE008E9597 /* SecureConversations */, 7594091329891C48008B173A /* Public */, 1A60AFC12566857200E53F53 /* Sources */, @@ -3504,6 +3517,32 @@ path = ProximityManager; sourceTree = ""; }; + C06152D22AB1BBEF00063BF8 /* SwiftUI */ = { + isa = PBXGroup; + children = ( + C0E948012AB1D5B100890026 /* Components */, + C06152D82AB1BC2F00063BF8 /* Managers */, + C06152D32AB1BBFD00063BF8 /* Extensions */, + ); + path = SwiftUI; + sourceTree = ""; + }; + C06152D32AB1BBFD00063BF8 /* Extensions */ = { + isa = PBXGroup; + children = ( + C06152D42AB1BC1300063BF8 /* Font+Extensions.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + C06152D82AB1BC2F00063BF8 /* Managers */ = { + isa = PBXGroup; + children = ( + C07F62442ABC3218003EFC97 /* OrientationManager */, + ); + path = Managers; + sourceTree = ""; + }; C06A757D296EC743006B69A2 /* VisitorCode */ = { isa = PBXGroup; children = ( @@ -3522,6 +3561,15 @@ path = NumberSlot; sourceTree = ""; }; + C07F62442ABC3218003EFC97 /* OrientationManager */ = { + isa = PBXGroup; + children = ( + C06152D92AB1BC4300063BF8 /* OrientationManager.swift */, + C07F62452ABC322B003EFC97 /* OrientationManager.Mock.swift */, + ); + path = OrientationManager; + sourceTree = ""; + }; C096B408297EBCEB00F0C552 /* CallVisualizer */ = { isa = PBXGroup; children = ( @@ -3647,6 +3695,32 @@ path = Mocks; sourceTree = ""; }; + C0E948012AB1D5B100890026 /* Components */ = { + isa = PBXGroup; + children = ( + C0E948072AB1D69C00890026 /* Header */, + C0E948022AB1D5BC00890026 /* Buttons */, + ); + path = Components; + sourceTree = ""; + }; + C0E948022AB1D5BC00890026 /* Buttons */ = { + isa = PBXGroup; + children = ( + C0E948032AB1D5D200890026 /* ActionButtonSwiftUI.swift */, + C0E948052AB1D64700890026 /* HeaderButtonSwiftUI.swift */, + ); + path = Buttons; + sourceTree = ""; + }; + C0E948072AB1D69C00890026 /* Header */ = { + isa = PBXGroup; + children = ( + C0E948082AB1D6AB00890026 /* HeaderSwiftUI.swift */, + ); + path = Header; + sourceTree = ""; + }; C42463722673ABCD0082C135 /* Screensharing */ = { isa = PBXGroup; children = ( @@ -4160,7 +4234,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "make write-diff\n"; + shellScript = "#make write-diff\n"; }; A5633E9F76E68066D5BFAF62 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -4225,6 +4299,7 @@ 1A6075E7258220E300569B0E /* UserImageStyle.swift in Sources */, 1ABD6C5D25B59D1C00D56EFA /* BubbleWindow.swift in Sources */, 75940964298D3889008B173A /* MessageRenderer.Web.swift in Sources */, + C0E948042AB1D5D200890026 /* ActionButtonSwiftUI.swift in Sources */, 1AE15E38257A578B00A642C0 /* MessageAlertConfiguration.swift in Sources */, C0175A132A56E29E001FACDE /* ChatMessageCardType.swift in Sources */, AFBBF5782851C391004993B3 /* Glia.Deprecated.swift in Sources */, @@ -4315,6 +4390,7 @@ 9AE0A7622822AF3000725946 /* FontScaling.Environment.Live.swift in Sources */, 1A0452DD25DBD0A4000DA0C1 /* HeaderButton.swift in Sources */, AF3D520B2983235C00AD8E69 /* FileUploader.Mock.swift in Sources */, + C0E948092AB1D6AB00890026 /* HeaderSwiftUI.swift in Sources */, AF39330B29B2A6A00008B60D /* ChatViewModel.SecureConverstaions.swift in Sources */, 75AF8CEF27DAA819009EEE2C /* SurveyViewController.swift in Sources */, 1A60AF96256675C400E53F53 /* UIColor+Extensions.swift in Sources */, @@ -4335,6 +4411,7 @@ 9A3E1D9427B6C29C005634EB /* ChatEngagementFile.Mock.swift in Sources */, 1A2DA73B25EFC00500032611 /* FileUploadListStyle.swift in Sources */, 7594095A298D386F008B173A /* NSLayoutConstraint+Extensions.swift in Sources */, + C07F62462ABC322B003EFC97 /* OrientationManager.Mock.swift in Sources */, C0D2F06829A4B71C00803B47 /* VideoCallViewModel.Mock.swift in Sources */, AFEF5C6F29928DB0005C3D8D /* SecureConversations.FileUploadView.swift in Sources */, 84D5B9622A14F33400807F92 /* QuickLookBased.Live.swift in Sources */, @@ -4414,6 +4491,7 @@ 9A19926B27D3BA8700161AAE /* ViewFactory.Environment.Mock.swift in Sources */, 84681A9B2A669D8800DD7406 /* QuickReplyView.swift in Sources */, 1A6EB05725A717CB0007081A /* ChatMessage.swift in Sources */, + C0E948062AB1D64700890026 /* HeaderButtonSwiftUI.swift in Sources */, 1AA738B225790D5A00E1120F /* AlertView.swift in Sources */, 845E2F8E283FB5B500C04D56 /* Theme.Survey.SingleQuestion.Accessibility.swift in Sources */, C47901B725ED2FB0007EE195 /* AlertViewController+ScreenShareOffer.swift in Sources */, @@ -4519,6 +4597,7 @@ 9AB196DE27C3FFF400FD60AB /* Call.Environment.Mock.swift in Sources */, 1A0C143125B8547200B00695 /* EngagementStyle.swift in Sources */, 7594098B298D38C2008B173A /* CallVisualizer+Presentation.swift in Sources */, + C06152DA2AB1BC4300063BF8 /* OrientationManager.swift in Sources */, 9A186A3727F5D38D0055886D /* ChatMessageEntryStyle.Accessibility.swift in Sources */, 9AB061C1280EFE09008960FA /* ChatFileDownloadStyle.Accessibility.swift in Sources */, 1A7CA8272574D6F40047CBBE /* ConnectStyle.swift in Sources */, @@ -4610,6 +4689,7 @@ 6E9C01AD26D3B8B500EBE1D4 /* OperatorTypingIndicatorView.swift in Sources */, AF10ED8B29B7A4C000E85309 /* ChatViewModel+ChoiceCards.swift in Sources */, 7594097E298D38C2008B173A /* CallVisualizer.BubbleIcon.swift in Sources */, + C06152D52AB1BC1300063BF8 /* Font+Extensions.swift in Sources */, AFA2FDF628907FC800428E6D /* BubbleStyle.Mock.swift in Sources */, 755D186B29A6A5830009F5E8 /* WelcomeStyle+MessageTitleStyle.swift in Sources */, 75940981298D38C2008B173A /* VisitorCodeView+NumberView.swift in Sources */, diff --git a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift index 1c7c662c0..6a5ab4f35 100644 --- a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift +++ b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift @@ -124,7 +124,8 @@ extension Glia { startSocketObservation: environment.coreSdk.startSocketObservation, stopSocketObservation: environment.coreSdk.stopSocketObservation, pushNotifications: environment.coreSdk.pushNotifications, - createSendMessagePayload: environment.coreSdk.createSendMessagePayload + createSendMessagePayload: environment.coreSdk.createSendMessagePayload, + orientationManager: environment.orientationManager ) ) rootCoordinator?.delegate = { [weak self] event in diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift index 7aca96ded..08ce4c92d 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift @@ -1,216 +1,87 @@ -import Foundation -import UIKit +import SwiftUI extension SecureConversations { - final class ConfirmationView: BaseView { - static let sideMargin = 24.0 - static let portraitConfirmationImageSize = 144.0 - static let landscapeConfirmationImageSize = 90.0 - - struct Props: Equatable { - let style: ConfirmationStyle - let header: Header.Props - let checkMessageButtonTap: Cmd - } - - private let header: Header - - var topRootStackViewConstraint: NSLayoutConstraint? - var confirmationImageViewWidthConstraints: NSLayoutConstraint? - var confirmationImageViewHeightConstraints: NSLayoutConstraint? - - lazy var rootStackView = UIStackView.make( - .vertical, - spacing: 0, - distribution: .fill, - alignment: .center - )( - confirmationImageView, - titleLabel, - subtitleLabel, - spacer, - checkMessagesButton - ) - - let confirmationImageView = UIImageView().makeView { imageView in - imageView.image = Asset.mcConfirmation.image.withRenderingMode(.alwaysTemplate) - } - let titleLabel = UILabel().makeView { label in - label.numberOfLines = 0 - label.textAlignment = .center - } - - let subtitleLabel = UILabel().makeView { label in - label.numberOfLines = 0 - label.textAlignment = .center - } - - // Flexible space to accommodate the check messages button - // at the bottom of the view. - let spacer = UIView() - - lazy var checkMessagesButton = UIButton(type: .custom).makeView { button in - button.addTarget( - self, - action: #selector(handleCheckMessagesButtonTap), - for: .touchUpInside - ) - - button.layer.cornerRadius = 4 - } - - var props: Props { - didSet { - renderProps() + struct ConfirmationViewSwiftUI: View { + @ObservedObject var model: Model + + var body: some View { + ZStack { + backgroundColor() + VStack(spacing: 0) { + HeaderSwiftUI(model: model.makeHeaderModel()) + VStack(spacing: 0) { + Spacer(minLength: 1) + checkmarkImage() + titleView() + subtitleView() + Spacer(minLength: 1) + confirmationButtonView() + } + .padding(.bottom, model.orientation.isPortrait ? 24 : 8) + .padding(.horizontal, 24) + } + .edgesIgnoringSafeArea(.top) } } + } +} - init(props: Props) { - self.header = Header( - props: props.header - ) - self.props = props - super.init() - } - - @available(*, unavailable) - required init() { - fatalError("init() has not been implemented") - } - - override func defineLayout() { - super.defineLayout() - defineHeaderLayout() - defineRootStackViewLayout() - defineConfirmationImageViewLayout() - defineTitleLabelLayout() - defineSubtitleLabelLayout() - defineSpacerLayout() - defineCheckMessagesButtonLayout() - renderProps() - } - - override func setup() { - super.setup() - addSubview(rootStackView) - } - - override func layoutSubviews() { - super.layoutSubviews() - - changeConfirmationImageViewDimensions() - } - - private func changeConfirmationImageViewDimensions() { - // The portrait factor is the factor between the space from the header - // to the beginning of the stack view versus the height of the screen - // in the Figma design. The landscape factor was calculated through trial - // and error to avoid a bug where the image was so big that it would hide - // the text below it. - let factor = currentOrientation.isPortrait ? 0.2783 : 0.075 - topRootStackViewConstraint?.constant = self.rootStackView.frame.height * factor - - let imageSize = currentOrientation.isPortrait ? - Self.portraitConfirmationImageSize : - Self.landscapeConfirmationImageSize - - confirmationImageViewWidthConstraints?.constant = imageSize - confirmationImageViewHeightConstraints?.constant = imageSize - } - - private func defineHeaderLayout() { - addSubview(header) - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - constraints += header.layoutInSuperview(edges: .horizontal) - constraints += header.layoutInSuperview(edges: .top) - } - - func defineRootStackViewLayout() { - topRootStackViewConstraint = rootStackView.topAnchor.constraint(equalTo: header.bottomAnchor) - NSLayoutConstraint.activate([ - rootStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Self.sideMargin), - rootStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -Self.sideMargin), - topRootStackViewConstraint, - rootStackView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -Self.sideMargin) - ].compactMap { $0 }) - } - - private func defineConfirmationImageViewLayout() { - confirmationImageViewWidthConstraints = confirmationImageView.widthAnchor.constraint( - equalToConstant: Self.portraitConfirmationImageSize - ) - confirmationImageViewHeightConstraints = confirmationImageView.heightAnchor.constraint( - equalToConstant: Self.portraitConfirmationImageSize - ) - - NSLayoutConstraint.activate([ - confirmationImageView.topAnchor.constraint(equalTo: rootStackView.topAnchor), - confirmationImageViewWidthConstraints, - confirmationImageViewHeightConstraints - ].compactMap { $0 }) - - rootStackView.setCustomSpacing(32, after: confirmationImageView) - } - - private func defineTitleLabelLayout() { - rootStackView.setCustomSpacing(16, after: titleLabel) - } - - private func defineSubtitleLabelLayout() { - rootStackView.setCustomSpacing(0, after: subtitleLabel) - } - - private func defineSpacerLayout() { - NSLayoutConstraint.activate([ - spacer.heightAnchor.constraint(greaterThanOrEqualToConstant: 1) - ]) - } - private func defineCheckMessagesButtonLayout() { - NSLayoutConstraint.activate([ - checkMessagesButton.widthAnchor.constraint( - equalTo: rootStackView.widthAnchor - ), - checkMessagesButton.heightAnchor.constraint(equalToConstant: 48) - ]) - } - @objc func handleCheckMessagesButtonTap() { - props.checkMessageButtonTap() - } - - private func renderProps() { - header.props = props.header - header.showCloseButton() - - confirmationImageView.tintColor = props.style.confirmationImageTint - titleLabel.text = props.style.titleStyle.text - titleLabel.textColor = props.style.titleStyle.color - titleLabel.font = props.style.titleStyle.font - setFontScalingEnabled( - props.style.titleStyle.accessibility.isFontScalingEnabled, - for: titleLabel - ) +private extension SecureConversations.ConfirmationViewSwiftUI { + @ViewBuilder + func backgroundColor() -> some View { + SwiftUI.Color(model.style.backgroundColor) + .edgesIgnoringSafeArea(.all) + } + @ViewBuilder + func checkmarkImage() -> some View { + SwiftUI.Image(uiImage: Asset.mcConfirmation.image.withRenderingMode(.alwaysTemplate)) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: model.orientation.isPortrait ? 100.0 : 70.0) + .foregroundColor(SwiftUI.Color(model.style.confirmationImageTint)) + .padding(.bottom, model.orientation.isPortrait ? 32 : 8) + .accessibility(hidden: true) + } - subtitleLabel.text = props.style.subtitleStyle.text - subtitleLabel.textColor = props.style.subtitleStyle.color - subtitleLabel.font = props.style.subtitleStyle.font - setFontScalingEnabled( - props.style.subtitleStyle.accessibility.isFontScalingEnabled, - for: subtitleLabel - ) + @ViewBuilder + func titleView() -> some View { + Text(model.style.titleStyle.text) + .font(.convert(model.style.titleStyle.font)) + .multilineTextAlignment(.center) + .foregroundColor(SwiftUI.Color(model.style.titleStyle.color)) + .padding(.bottom, model.orientation.isPortrait ? 16 : 8) + } - checkMessagesButton.setTitle(props.style.checkMessagesButtonStyle.title, for: .normal) - checkMessagesButton.setTitleColor(props.style.checkMessagesButtonStyle.textColor, for: .normal) - checkMessagesButton.backgroundColor = props.style.checkMessagesButtonStyle.backgroundColor - checkMessagesButton.accessibilityTraits = .button - checkMessagesButton.accessibilityIdentifier = "secureConversations_confirmationCheckMessages_button" - checkMessagesButton.accessibilityLabel = props.style.checkMessagesButtonStyle.accessibility.label - checkMessagesButton.accessibilityHint = props.style.checkMessagesButtonStyle.accessibility.hint - setFontScalingEnabled( - props.style.checkMessagesButtonStyle.accessibility.isFontScalingEnabled, - for: checkMessagesButton - ) + @ViewBuilder + func subtitleView() -> some View { + Text(model.style.subtitleStyle.text) + .font(.convert(model.style.subtitleStyle.font)) + .multilineTextAlignment(.center) + .lineLimit(nil) + .foregroundColor(SwiftUI.Color(model.style.subtitleStyle.color)) + } - backgroundColor = props.style.backgroundColor - } + @ViewBuilder + func confirmationButtonView() -> some View { + SwiftUI.Button { + model.event(.chatTranscriptScreenRequested) + } label: { + Text(model.style.checkMessagesButtonStyle.title) + .font(.convert(model.style.checkMessagesButtonStyle.font)) + .multilineTextAlignment(.center) + .foregroundColor(SwiftUI.Color(model.style.checkMessagesButtonStyle.textColor)) + .padding(.vertical, 4) + .padding(.horizontal, 16) + .frame( + maxWidth: .infinity, + minHeight: 48, + idealHeight: 48 + ) + .background(SwiftUI.Color(model.style.checkMessagesButtonStyle.backgroundColor)) + .cornerRadius(4) + } + .accessibility(identifier: "secureConversations_confirmationCheckMessages_button") + .accessibility(label: Text(model.style.checkMessagesButtonStyle.accessibility.label)) + .accessibility(hint: Text(model.style.checkMessagesButtonStyle.accessibility.hint)) } } diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift index c1904fca1..053cf7374 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift @@ -1,25 +1,14 @@ import UIKit +import SwiftUI extension SecureConversations { final class ConfirmationViewController: UIViewController { - var props: Props { - didSet { - guard props != oldValue else { return } - renderProps() - } - } - - private let viewFactory: ViewFactory - private let viewModel: ConfirmationViewModel + private let model: ConfirmationViewSwiftUI.Model init( - viewModel: ConfirmationViewModel, - viewFactory: ViewFactory, - props: Props + model: ConfirmationViewSwiftUI.Model ) { - self.viewModel = viewModel - self.viewFactory = viewFactory - self.props = props + self.model = model super.init(nibName: nil, bundle: nil) } @@ -30,26 +19,22 @@ extension SecureConversations { override func loadView() { super.loadView() - renderProps() - } + let hostingController: UIHostingController + let confirmationView = ConfirmationViewSwiftUI( + model: model + ) - func renderProps() { - let confirmationView: ConfirmationView - if let currentView = view as? ConfirmationView { - confirmationView = currentView - } else { - confirmationView = viewFactory.makeSecureConversationsConfirmationView( - props: props.confirmationViewProps - ) - view = confirmationView - } - confirmationView.props = props.confirmationViewProps + hostingController = UIHostingController(rootView: confirmationView) + addChild(hostingController) + view.addSubview(hostingController.view) + hostingController.didMove(toParent: self) + hostingController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + hostingController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) } } } - -extension SecureConversations.ConfirmationViewController { - struct Props: Equatable { - let confirmationViewProps: SecureConversations.ConfirmationView.Props - } -} diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift index f21b60899..0dac97c78 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift @@ -1,87 +1,99 @@ import Foundation +import UIKit +import Combine -extension SecureConversations { - final class ConfirmationViewModel: ViewModel { - var action: ((Action) -> Void)? +extension SecureConversations.ConfirmationViewSwiftUI { + final class Model: ObservableObject { + @Published private(set) var orientation: UIInterfaceOrientation + let environment: Environment + let style: SecureConversations.ConfirmationStyle var delegate: ((DelegateEvent) -> Void)? - var environment: Environment + let orientationManager: OrientationManager + var cancellables: Set = [] - init(environment: Environment) { + init( + environment: Environment, + style: SecureConversations.ConfirmationStyle, + delegate: ((DelegateEvent) -> Void)? + ) { self.environment = environment + self.style = style + self.delegate = delegate + self.orientationManager = environment.orientationManager + self.orientation = orientationManager.orientation + orientationManager.$orientation.sink { [weak self] orientation in + self?.orientation = orientation + }.store(in: &self.cancellables) } + } +} - func event(_ event: Event) { - switch event { - case .closeTapped: - delegate?(.closeTapped) - } - } - - func reportChange() { - delegate?(.renderProps(props())) +// MARK: - Public Methods +extension SecureConversations.ConfirmationViewSwiftUI.Model { + func event(_ event: Event) { + switch event { + case .closeTapped: + delegate?(.closeTapped) + case .chatTranscriptScreenRequested: + delegate?(.chatTranscriptScreenRequested) } } } -extension SecureConversations.ConfirmationViewModel { - func props() -> SecureConversations.ConfirmationViewController.Props { - let confirmationStyle = environment.confirmationStyle - let confirmationViewProps = SecureConversations.ConfirmationView.Props( - style: confirmationStyle, - header: Self.buildHeaderProps( - style: confirmationStyle, - closeButtonCmd: Cmd(closure: { [weak self] in self?.delegate?(.closeTapped) }) - ), - checkMessageButtonTap: Cmd { [weak self] in self?.delegate?(.chatTranscriptScreenRequested) } +// MARK: - Private Methods +extension SecureConversations.ConfirmationViewSwiftUI.Model { + func makeHeaderModel() -> HeaderSwiftUI.Model { + let endButtonProps: ActionButtonSwiftUI.Model = .init( + style: style.header.endButton, + accessibilityIdentifier: "header_end_button", + isEnabled: false, + isHidden: true ) - let viewControllerProps = SecureConversations.ConfirmationViewController.Props( - confirmationViewProps: confirmationViewProps + let closeButtonProps: HeaderButtonSwiftUI.Model = .init( + tap: Cmd(closure: { [weak self] in + self?.delegate?(.closeTapped) + }), + style: style.header.closeButton, + isEnabled: true, + isHidden: false ) - return viewControllerProps - } + let endScreenShareButtonProps: HeaderButtonSwiftUI.Model = .init( + style: style.header.endScreenShareButton, + isEnabled: false, + isHidden: true + ) - static func buildHeaderProps( - style: SecureConversations.ConfirmationStyle, - closeButtonCmd: Cmd - ) -> Header.Props { - let backButton = style.header.backButton.map { HeaderButton.Props(style: $0) } + let environment: HeaderSwiftUI.Environment = .init(uiApplication: environment.uiApplication) - return Header.Props( + return .init( title: style.headerTitle, effect: .none, - endButton: .init(style: style.header.endButton, accessibilityIdentifier: "header_end_button"), - backButton: backButton, - closeButton: .init(tap: closeButtonCmd, style: style.header.closeButton), - endScreenshareButton: .init(style: style.header.endScreenShareButton), - style: style.header + endButton: endButtonProps, + backButton: nil, + closeButton: closeButtonProps, + endScreenshareButton: endScreenShareButtonProps, + style: style.header, + environment: environment ) } } -extension SecureConversations.ConfirmationViewModel { +// MARK: - Objects +extension SecureConversations.ConfirmationViewSwiftUI.Model { enum Event { case closeTapped - } - - enum Action { - case start + case chatTranscriptScreenRequested } enum DelegateEvent { case closeTapped - case renderProps(SecureConversations.ConfirmationViewController.Props) case chatTranscriptScreenRequested } - enum StartAction { - case none - } -} - -extension SecureConversations.ConfirmationViewModel { struct Environment { - var confirmationStyle: SecureConversations.ConfirmationStyle + var orientationManager: OrientationManager + var uiApplication: UIKitBased.UIApplication } } diff --git a/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift b/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift index 942ae8ef7..b40c4f48b 100644 --- a/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift +++ b/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift @@ -12,7 +12,7 @@ extension Theme { let titleStyle = SecureConversations.ConfirmationStyle.TitleStyle( text: Confirmation.title, - font: font.header3, + font: font.header1, color: color.baseDark, accessibility: .init(isFontScalingEnabled: true) ) diff --git a/GliaWidgets/SecureConversations/SecureConversations.Coordinator.swift b/GliaWidgets/SecureConversations/SecureConversations.Coordinator.swift index 9eac3423e..728c494c9 100644 --- a/GliaWidgets/SecureConversations/SecureConversations.Coordinator.swift +++ b/GliaWidgets/SecureConversations/SecureConversations.Coordinator.swift @@ -160,29 +160,24 @@ extension SecureConversations { } func presentSecureConversationsConfirmationViewController() { - let viewModel = SecureConversations.ConfirmationViewModel( - environment: .init( - confirmationStyle: viewFactory.theme.secureConversationsConfirmation - ) + let environment: ConfirmationViewSwiftUI.Model.Environment = .init( + orientationManager: environment.orientationManager, + uiApplication: environment.uiApplication ) - let controller = SecureConversations.ConfirmationViewController( - viewModel: viewModel, - viewFactory: viewFactory, - props: viewModel.props() - ) + let model = SecureConversations.ConfirmationViewSwiftUI.Model( + environment: environment, + style: viewFactory.theme.secureConversationsConfirmation, + delegate: { [weak self] event in + switch event { + case .closeTapped: + self?.delegate?(.closeTapped(.doNotPresentSurvey)) + case .chatTranscriptScreenRequested: + self?.navigateToTranscript() + } + }) - viewModel.delegate = { [weak self, weak controller] event in - switch event { - case .closeTapped: - self?.delegate?(.closeTapped(.doNotPresentSurvey)) - // Bind changes in view model to view controller. - case let .renderProps(props): - controller?.props = props - case .chatTranscriptScreenRequested: - self?.navigateToTranscript() - } - } + let controller = SecureConversations.ConfirmationViewController(model: model) self.navigationPresenter.push( controller, @@ -326,6 +321,7 @@ extension SecureConversations.Coordinator { var uuid: () -> UUID var uiApplication: UIKitBased.UIApplication var uiScreen: UIKitBased.UIScreen + var uiDevice: UIKitBased.UIDevice var notificationCenter: FoundationBased.NotificationCenter var createFileUploadListModel: SecureConversations.FileUploadListViewModel.Create var viewFactory: ViewFactory @@ -351,6 +347,7 @@ extension SecureConversations.Coordinator { var startSocketObservation: CoreSdkClient.StartSocketObservation var stopSocketObservation: CoreSdkClient.StopSocketObservation var createSendMessagePayload: CoreSdkClient.CreateSendMessagePayload + var orientationManager: OrientationManager } enum DelegateEvent { diff --git a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift index 7b00d421d..7247c6583 100644 --- a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift +++ b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift @@ -34,7 +34,8 @@ extension EngagementCoordinator.Environment { startSocketObservation: {}, stopSocketObservation: {}, pushNotifications: .mock, - createSendMessagePayload: { _, _ in .mock() } + createSendMessagePayload: { _, _ in .mock() }, + orientationManager: .mock() ) } #endif diff --git a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.swift b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.swift index 412f4eeea..e59d803ed 100644 --- a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.swift +++ b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.swift @@ -36,5 +36,6 @@ extension EngagementCoordinator { var stopSocketObservation: CoreSdkClient.StopSocketObservation var pushNotifications: CoreSdkClient.PushNotifications var createSendMessagePayload: CoreSdkClient.CreateSendMessagePayload + var orientationManager: OrientationManager } } diff --git a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift index b68835c0c..6d972ab51 100644 --- a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift +++ b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift @@ -452,6 +452,7 @@ extension EngagementCoordinator { uuid: environment.uuid, uiApplication: environment.uiApplication, uiScreen: environment.uiScreen, + uiDevice: environment.uiDevice, notificationCenter: environment.notificationCenter, createFileUploadListModel: environment.createFileUploadListModel, viewFactory: viewFactory, @@ -476,7 +477,8 @@ extension EngagementCoordinator { isAuthenticated: environment.isAuthenticated, startSocketObservation: environment.startSocketObservation, stopSocketObservation: environment.stopSocketObservation, - createSendMessagePayload: environment.createSendMessagePayload + createSendMessagePayload: environment.createSendMessagePayload, + orientationManager: environment.orientationManager ) ) diff --git a/GliaWidgets/Sources/FoundationBased/FoundationBased.Interface.swift b/GliaWidgets/Sources/FoundationBased/FoundationBased.Interface.swift index ef9375c23..1771ad388 100644 --- a/GliaWidgets/Sources/FoundationBased/FoundationBased.Interface.swift +++ b/GliaWidgets/Sources/FoundationBased/FoundationBased.Interface.swift @@ -1,4 +1,5 @@ import Foundation +import Combine enum FoundationBased { struct FileManager { @@ -92,6 +93,8 @@ enum FoundationBased { func removeObserver(_ observer: Any) { removeObserverClosure(observer) } + + var publisherForNotification: (NSNotification.Name) -> AnyPublisher } } diff --git a/GliaWidgets/Sources/FoundationBased/FoundationBased.Live.swift b/GliaWidgets/Sources/FoundationBased/FoundationBased.Live.swift index 1ec27b82f..9b7e3fe29 100644 --- a/GliaWidgets/Sources/FoundationBased/FoundationBased.Live.swift +++ b/GliaWidgets/Sources/FoundationBased/FoundationBased.Live.swift @@ -1,4 +1,5 @@ import Foundation +import Combine extension FoundationBased.FileManager { static let live = Self( @@ -65,6 +66,7 @@ extension FoundationBased.NotificationCenter { static let live = Self( addObserverClosure: NotificationCenter.default.addObserver, removeObserverClosure: NotificationCenter.default.removeObserver, - removeObserverWithNameAndObject: NotificationCenter.default.removeObserver + removeObserverWithNameAndObject: NotificationCenter.default.removeObserver, + publisherForNotification: { NotificationCenter.default.publisher(for: $0).eraseToAnyPublisher() } ) } diff --git a/GliaWidgets/Sources/FoundationBased/FoundationBased.Mock.swift b/GliaWidgets/Sources/FoundationBased/FoundationBased.Mock.swift index c82154df5..032c92f21 100644 --- a/GliaWidgets/Sources/FoundationBased/FoundationBased.Mock.swift +++ b/GliaWidgets/Sources/FoundationBased/FoundationBased.Mock.swift @@ -1,5 +1,6 @@ #if DEBUG import Foundation +import Combine extension FoundationBased.FileManager { static let mock = Self( @@ -50,7 +51,10 @@ extension FoundationBased.NotificationCenter { static let mock = Self( addObserverClosure: { _, _, _, _ in }, removeObserverClosure: { _ in }, - removeObserverWithNameAndObject: { _, _, _ in } + removeObserverWithNameAndObject: { _, _, _ in }, + publisherForNotification: { _ in + Just(Notification(name: NSNotification.Name(rawValue: ""))).eraseToAnyPublisher() + } ) } diff --git a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Interface.swift b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Interface.swift index f50d316d8..efb801dd0 100644 --- a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Interface.swift +++ b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Interface.swift @@ -44,6 +44,7 @@ extension Glia { var createFileUploadListModel: SecureConversations.FileUploadListViewModel.Create var screenShareHandler: ScreenShareHandler var messagesWithUnreadCountLoaderScheduler: CoreSdkClient.ReactiveSwift.DateScheduler + var orientationManager: OrientationManager } } diff --git a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift index aeece0fc4..72c9717b7 100644 --- a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift +++ b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift @@ -27,7 +27,12 @@ extension Glia.Environment { createFileUploader: FileUploader.init(maximumUploads:environment:), createFileUploadListModel: SecureConversations.FileUploadListViewModel.init, screenShareHandler: ScreenShareHandler.create(), - messagesWithUnreadCountLoaderScheduler: CoreSdkClient.ReactiveSwift.QueueScheduler.main + messagesWithUnreadCountLoaderScheduler: CoreSdkClient.ReactiveSwift.QueueScheduler.main, + orientationManager: .init(environment: .init( + uiApplication: .live, + uiDevice: .live, + notificationCenter: .live + )) ) } diff --git a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift index bc1b20de8..013108965 100644 --- a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift +++ b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift @@ -25,7 +25,8 @@ extension Glia.Environment { createFileUploader: FileUploader.mock, createFileUploadListModel: SecureConversations.FileUploadListViewModel.mock(environment:), screenShareHandler: .mock, - messagesWithUnreadCountLoaderScheduler: CoreSdkClient.reactiveSwiftDateSchedulerMock + messagesWithUnreadCountLoaderScheduler: CoreSdkClient.reactiveSwiftDateSchedulerMock, + orientationManager: .mock() ) } diff --git a/GliaWidgets/Sources/UIKitBased/UIKitBased.Interface.swift b/GliaWidgets/Sources/UIKitBased/UIKitBased.Interface.swift index 81bcc5349..c1f8a3ab4 100644 --- a/GliaWidgets/Sources/UIKitBased/UIKitBased.Interface.swift +++ b/GliaWidgets/Sources/UIKitBased/UIKitBased.Interface.swift @@ -17,6 +17,7 @@ enum UIKitBased { struct UIDevice { var proximityState: () -> Bool var isProximityMonitoringEnabled: (Bool) -> Void + var orientationDidChangeNotification: () -> NSNotification.Name } struct UIScreen { diff --git a/GliaWidgets/Sources/UIKitBased/UIKitBased.Live.swift b/GliaWidgets/Sources/UIKitBased/UIKitBased.Live.swift index 51ab52b4a..7527cf763 100644 --- a/GliaWidgets/Sources/UIKitBased/UIKitBased.Live.swift +++ b/GliaWidgets/Sources/UIKitBased/UIKitBased.Live.swift @@ -18,7 +18,8 @@ extension UIKitBased.UIApplication { extension UIKitBased.UIDevice { static let live = Self.init( proximityState: { UIDevice.current.proximityState }, - isProximityMonitoringEnabled: { UIDevice.current.isProximityMonitoringEnabled = $0 } + isProximityMonitoringEnabled: { UIDevice.current.isProximityMonitoringEnabled = $0 }, + orientationDidChangeNotification: { UIDevice.orientationDidChangeNotification } ) } diff --git a/GliaWidgets/Sources/UIKitBased/UIKitBased.Mock.swift b/GliaWidgets/Sources/UIKitBased/UIKitBased.Mock.swift index 458f5c3d8..3c0eb769d 100644 --- a/GliaWidgets/Sources/UIKitBased/UIKitBased.Mock.swift +++ b/GliaWidgets/Sources/UIKitBased/UIKitBased.Mock.swift @@ -29,7 +29,8 @@ extension UIImage { extension UIKitBased.UIDevice { static let mock = Self.init( proximityState: { .init() }, - isProximityMonitoringEnabled: { _ in } + isProximityMonitoringEnabled: { _ in }, + orientationDidChangeNotification: { .init("") } ) } diff --git a/GliaWidgets/Sources/ViewFactory/ViewFactory.swift b/GliaWidgets/Sources/ViewFactory/ViewFactory.swift index 0dfb41c53..5ed46237b 100644 --- a/GliaWidgets/Sources/ViewFactory/ViewFactory.swift +++ b/GliaWidgets/Sources/ViewFactory/ViewFactory.swift @@ -136,8 +136,4 @@ class ViewFactory { ) -> SecureConversations.WelcomeView { return .init(props: props, environment: environment) } - - func makeSecureConversationsConfirmationView(props: SecureConversations.ConfirmationView.Props) -> SecureConversations.ConfirmationView { - return .init(props: props) - } } diff --git a/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift new file mode 100644 index 000000000..77fe8c833 --- /dev/null +++ b/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift @@ -0,0 +1,65 @@ +import SwiftUI + +struct ActionButtonSwiftUI: View { + static let edgeInsets: EdgeInsets = .init(top: 6, leading: 16, bottom: 6, trailing: 16) + @ObservedObject var model: Model + + var body: some View { + Text(model.style.title) + .font(.convert(model.style.titleFont)) + .foregroundColor(SwiftUI.Color(model.style.titleColor)) + .padding(Self.edgeInsets) + .background(SwiftUI.Color(model.style.backgroundColor.color)) + .cornerRadius(model.style.cornerRaidus ?? 0) + .overlay( + RoundedRectangle( + cornerRadius: model.style.cornerRaidus ?? 0) + .stroke( + SwiftUI.Color(model.style.borderColor ?? .clear), + lineWidth: model.style.borderWidth ?? 0 + ) + ) + .shadow( + color: SwiftUI.Color(model.style.shadowColor ?? .clear), + radius: model.style.shadowRadius ?? 0, + x: model.style.shadowOffset?.width ?? 0, + y: model.style.shadowOffset?.height ?? 0 + ) + .accessibility(identifier: model.accessibilityIdentifier) + .accessibility(addTraits: .isButton) + .accessibility(removeTraits: .isImage) + .onTapGesture(perform: model.tap.callAsFunction) + } +} + +extension ActionButtonSwiftUI { + final class Model: ObservableObject { + let style: ActionButtonStyle + let height: CGFloat + let tap: Cmd + let accessibilityIdentifier: String + @Published var isEnabled: Bool + @Published var isHidden: Bool + + init( + style: ActionButtonStyle = .init( + title: "", + titleFont: .systemFont(ofSize: 16), + titleColor: .white, + backgroundColor: .fill(color: .blue) + ), + height: CGFloat = 40, + tap: Cmd = .nop, + accessibilityIdentifier: String = "", + isEnabled: Bool, + isHidden: Bool + ) { + self.style = style + self.height = height + self.tap = tap + self.accessibilityIdentifier = accessibilityIdentifier.isEmpty ? style.title : accessibilityIdentifier + self.isEnabled = isEnabled + self.isHidden = isHidden + } + } +} diff --git a/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift new file mode 100644 index 000000000..34e24658d --- /dev/null +++ b/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift @@ -0,0 +1,48 @@ +import SwiftUI + +struct HeaderButtonSwiftUI: View { + @ObservedObject var model: Model + + var body: some View { + SwiftUI.Image(uiImage: model.style.image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame( + width: model.size.width, + height: model.size.height + ) + .padding(.horizontal, 8) + .padding(.vertical, 6) + .contentShape(Rectangle()) + .foregroundColor(SwiftUI.Color(model.style.color)) + .opacity(model.isEnabled ? 1.0 : 0.6) + .accessibility(label: Text(model.style.accessibility.label)) + .accessibility(addTraits: .isButton) + .accessibility(removeTraits: .isImage) + .onTapGesture(perform: model.tap.callAsFunction) + } +} + +extension HeaderButtonSwiftUI { + final class Model: ObservableObject { + var tap: Cmd + var style: HeaderButtonStyle + var size: CGSize + var isEnabled: Bool + var isHidden: Bool + + init( + tap: Cmd = .nop, + style: HeaderButtonStyle, + size: CGSize = CGSize(width: 14, height: 14), + isEnabled: Bool, + isHidden: Bool + ) { + self.tap = tap + self.style = style + self.size = size + self.isEnabled = isEnabled + self.isHidden = isHidden + } + } +} diff --git a/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift new file mode 100644 index 000000000..1c64e7d3f --- /dev/null +++ b/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift @@ -0,0 +1,86 @@ +import SwiftUI + +struct HeaderSwiftUI: View { + @ObservedObject var model: Model + + var body: some View { + ZStack(alignment: .bottom) { + HStack(spacing: 16) { + if let backButton = model.backButton { + HeaderButtonSwiftUI(model: backButton) + } + + Spacer() + if !model.endButton.isHidden { + ActionButtonSwiftUI(model: model.endButton) + } + + if !model.endScreenshareButton.isHidden { + HeaderButtonSwiftUI(model: model.endScreenshareButton) + } + + if !model.closeButton.isHidden { + HeaderButtonSwiftUI(model: model.closeButton) + } + } + Text(model.title) + .font(.convert(model.style.titleFont)) + .foregroundColor(SwiftUI.Color(model.style.titleColor)) + .accessibility(identifier: "header_view_title_label") + .accessibility(label: Text(model.title)) + .accessibility(addTraits: .isHeader) + } + .padding(.horizontal, 16) + .padding(.bottom, 12) + .frame( + height: 58 + (model.environment.uiApplication.windows().first?.safeAreaInsets.top ?? 0), + alignment: .bottom + ) + .background(SwiftUI.Color(model.style.backgroundColor.color)) + .edgesIgnoringSafeArea([.leading, .trailing]) + } +} + +extension HeaderSwiftUI { + final class Model: ObservableObject { + let title: String + let effect: Effect + let endButton: ActionButtonSwiftUI.Model + let backButton: HeaderButtonSwiftUI.Model? + let closeButton: HeaderButtonSwiftUI.Model + let endScreenshareButton: HeaderButtonSwiftUI.Model + let style: HeaderStyle + let environment: Environment + + init( + title: String, + effect: Effect, + endButton: ActionButtonSwiftUI.Model, + backButton: HeaderButtonSwiftUI.Model?, + closeButton: HeaderButtonSwiftUI.Model, + endScreenshareButton: HeaderButtonSwiftUI.Model, + style: HeaderStyle, + environment: Environment + ) { + self.title = title + self.effect = effect + self.endButton = endButton + self.backButton = backButton + self.closeButton = closeButton + self.endScreenshareButton = endScreenshareButton + self.style = style + self.environment = environment + } + } +} + +extension HeaderSwiftUI { + enum Effect { + case none + case blur + } + + struct Environment { + let uiApplication: UIKitBased.UIApplication + } +} diff --git a/GliaWidgets/SwiftUI/Extensions/Font+Extensions.swift b/GliaWidgets/SwiftUI/Extensions/Font+Extensions.swift new file mode 100644 index 000000000..7b20072ab --- /dev/null +++ b/GliaWidgets/SwiftUI/Extensions/Font+Extensions.swift @@ -0,0 +1,7 @@ +import SwiftUI + +extension Font { + static func convert(_ uiFont: UIFont) -> Font { + return .custom(uiFont.familyName + uiFont.fontName, size: uiFont.pointSize) + } +} diff --git a/GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.Mock.swift b/GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.Mock.swift new file mode 100644 index 000000000..0a0879eb3 --- /dev/null +++ b/GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.Mock.swift @@ -0,0 +1,19 @@ +import Foundation + +#if DEBUG + +extension OrientationManager { + static func mock( + uiApplication: UIKitBased.UIApplication = .mock, + uiDevice: UIKitBased.UIDevice = .mock, + notificationCenter: FoundationBased.NotificationCenter = .mock + ) -> OrientationManager { + .init(environment: .init( + uiApplication: uiApplication, + uiDevice: uiDevice, + notificationCenter: notificationCenter + )) + } +} + +#endif diff --git a/GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.swift b/GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.swift new file mode 100644 index 000000000..a3f626c69 --- /dev/null +++ b/GliaWidgets/SwiftUI/Managers/OrientationManager/OrientationManager.swift @@ -0,0 +1,38 @@ +import SwiftUI +import Combine + +final class OrientationManager: ObservableObject { + @Published private(set) var orientation: UIInterfaceOrientation + + private let environment: Environment + private var orientationSubscription: AnyCancellable? + private var currentOrientation: UIInterfaceOrientation { + environment.uiApplication.windows().first?.windowScene?.interfaceOrientation ?? .portrait + } + + var isPortrait: Bool { + orientation == .portrait || orientation == .portraitUpsideDown + } + + var isLandscape: Bool { + !isPortrait + } + + init(environment: Environment) { + self.environment = environment + orientation = environment.uiApplication.windows().first?.windowScene?.interfaceOrientation ?? .portrait + orientationSubscription = environment.notificationCenter + .publisherForNotification(environment.uiDevice.orientationDidChangeNotification()) + .map { _ in self.currentOrientation } + .removeDuplicates() + .assign(to: \.orientation, on: self) + } +} + +extension OrientationManager { + struct Environment { + var uiApplication: UIKitBased.UIApplication + var uiDevice: UIKitBased.UIDevice + var notificationCenter: FoundationBased.NotificationCenter + } +} diff --git a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift index b16e5e1c4..b40ba6765 100644 --- a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift @@ -27,9 +27,10 @@ extension HeaderStyle { extension HeaderButtonStyle { static func mock( image: UIImage = .mock, - color: UIColor = .white + color: UIColor = .white, + accessibility: Accessibility = .init(label: "", hint: "") ) -> HeaderButtonStyle { - return .init(image: image, color: color) + return .init(image: image, color: color, accessibility: accessibility) } } diff --git a/GliaWidgetsTests/Coordinator/RootCoordinator.Environment.Failing.swift b/GliaWidgetsTests/Coordinator/RootCoordinator.Environment.Failing.swift index b339631f5..366c4165a 100644 --- a/GliaWidgetsTests/Coordinator/RootCoordinator.Environment.Failing.swift +++ b/GliaWidgetsTests/Coordinator/RootCoordinator.Environment.Failing.swift @@ -85,6 +85,7 @@ extension EngagementCoordinator.Environment { createSendMessagePayload: { _, _ in fail("\(Self.self).createSendMessagePayload") return .mock() - } + }, + orientationManager: .mock() ) } diff --git a/GliaWidgetsTests/FoundationBased.Failing.swift b/GliaWidgetsTests/FoundationBased.Failing.swift index c3254f1bb..6dfa53e0a 100644 --- a/GliaWidgetsTests/FoundationBased.Failing.swift +++ b/GliaWidgetsTests/FoundationBased.Failing.swift @@ -1,4 +1,5 @@ @testable import GliaWidgets +import Combine extension FoundationBased.FileManager { static let failing = Self( @@ -89,6 +90,10 @@ extension FoundationBased.NotificationCenter { }, removeObserverWithNameAndObject: {_, _, _ in fail("\(Self.self).removeObserverWithNameAndObject") + }, + publisherForNotification: { _ in + fail("\(Self.self).publisherForNotification") + return Empty().eraseToAnyPublisher() } ) } diff --git a/GliaWidgetsTests/Glia.Environment.Failing.swift b/GliaWidgetsTests/Glia.Environment.Failing.swift index fe3856b3d..14ba7bcff 100644 --- a/GliaWidgetsTests/Glia.Environment.Failing.swift +++ b/GliaWidgetsTests/Glia.Environment.Failing.swift @@ -54,7 +54,8 @@ extension Glia.Environment { return .mock() }, screenShareHandler: .mock, - messagesWithUnreadCountLoaderScheduler: CoreSdkClient.reactiveSwiftDateSchedulerMock + messagesWithUnreadCountLoaderScheduler: CoreSdkClient.reactiveSwiftDateSchedulerMock, + orientationManager: .mock() ) } diff --git a/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.Mock.swift b/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.Mock.swift index 383ed28f0..85b8203a4 100644 --- a/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.Mock.swift +++ b/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.Mock.swift @@ -1,14 +1,73 @@ -import Foundation +import UIKit @testable import GliaWidgets -extension SecureConversations.ConfirmationViewModel { - static let mock = SecureConversations.ConfirmationViewModel( - environment: .mock - ) +extension SecureConversations.ConfirmationStyle { + static func mock( + title: String = "", + titleStyle: TitleStyle = .mock(), + subtitleStyle: SubtitleStyle = .mock(), + checkMessagesButtonStyle: CheckMessagesButtonStyle = .mock() + ) -> SecureConversations.ConfirmationStyle { + .init( + header: .mock(), + headerTitle: title, + confirmationImage: .mock, + confirmationImageTint: Color.baseLight, + titleStyle: titleStyle, + subtitleStyle: subtitleStyle, + checkMessagesButtonStyle: checkMessagesButtonStyle, + backgroundColor: Color.baseLight + ) + } } -extension SecureConversations.ConfirmationViewModel.Environment { - static let mock = SecureConversations.ConfirmationViewModel.Environment( - confirmationStyle: Theme().secureConversationsConfirmation - ) +extension SecureConversations.ConfirmationStyle.TitleStyle { + static func mock( + text: String = "Title label", + font: UIFont = ThemeFont().header1, + color: UIColor = Color.baseDark, + accessibility: Accessibility = .unsupported + ) -> SecureConversations.ConfirmationStyle.TitleStyle { + return .init( + text: text, + font: font, + color: color, + accessibility: accessibility + ) + } } + +extension SecureConversations.ConfirmationStyle.SubtitleStyle { + static func mock( + text: String = "Title label", + font: UIFont = ThemeFont().header1, + color: UIColor = Color.baseDark, + accessibility: Accessibility = .unsupported + ) -> SecureConversations.ConfirmationStyle.SubtitleStyle { + return .init( + text: text, + font: font, + color: color, + accessibility: accessibility + ) + } +} + +extension SecureConversations.ConfirmationStyle.CheckMessagesButtonStyle { + static func mock( + title: String = "Title label", + font: UIFont = ThemeFont().header1, + textColor: UIColor = Color.baseDark, + backgroundColor: UIColor = Color.baseLight, + accessibility: Accessibility = .unsupported + ) -> SecureConversations.ConfirmationStyle.CheckMessagesButtonStyle { + return .init( + title: title, + font: font, + textColor: textColor, + backgroundColor: backgroundColor, + accessibility: accessibility + ) + } +} + diff --git a/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModelTests.swift b/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModelTests.swift index ddf345042..a1d6cc5d5 100644 --- a/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModelTests.swift +++ b/GliaWidgetsTests/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModelTests.swift @@ -3,37 +3,35 @@ import XCTest @testable import GliaWidgets final class SecureConversationsConfirmationViewModelTests: XCTestCase { - typealias ConfirmationViewModel = SecureConversations.ConfirmationViewModel - var viewModel: ConfirmationViewModel = .mock - - override func setUp() { - viewModel = .mock - } + typealias ConfirmationViewModel = SecureConversations.ConfirmationViewSwiftUI.Model + + var viewModel: ConfirmationViewModel = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: Theme().defaultSecureConversationsConfirmationStyle, + delegate: nil + ) } // Props extension SecureConversationsConfirmationViewModelTests { func testPropsDoNotGenerateABackButton() { - let props = viewModel.props().confirmationViewProps.header + let backButton = viewModel.style.header.backButton - XCTAssertNil(props.backButton) + XCTAssertNil(backButton) } func testPropsGenerateCorrectTitle() { let title = "Test" - var style = Theme().secureConversationsConfirmation - style.headerTitle = title - - viewModel.environment = .init(confirmationStyle: style) - - let props = viewModel.props() - XCTAssertEqual(props.confirmationViewProps.header.title, title) - } - - func testPropsGenerateEndButtonWithAccessibilityIdentifier() { - let props = viewModel.props().confirmationViewProps.header.endButton - - XCTAssertEqual(props.accessibilityIdentifier, "header_end_button") + viewModel = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: .mock(title: title), + delegate: nil + ) + XCTAssertEqual(viewModel.style.headerTitle, title) } } @@ -58,11 +56,16 @@ extension SecureConversationsConfirmationViewModelTests { func testPressingCloseButtonCallsDelegate() throws { var receivedEvent: ConfirmationViewModel.DelegateEvent? - viewModel.delegate = { event in - receivedEvent = event - } - - viewModel.props().confirmationViewProps.header.closeButton.tap() + viewModel = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: .mock(), + delegate: { event in + receivedEvent = event + } + ) + viewModel.delegate?(.closeTapped) switch try XCTUnwrap(receivedEvent) { case .closeTapped: @@ -74,11 +77,16 @@ extension SecureConversationsConfirmationViewModelTests { func testPressingCheckMessagesButtonCallsDelegate() throws { var receivedEvent: ConfirmationViewModel.DelegateEvent? - viewModel.delegate = { event in - receivedEvent = event - } - - viewModel.props().confirmationViewProps.checkMessageButtonTap() + viewModel = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: .mock(), + delegate: { event in + receivedEvent = event + } + ) + viewModel.delegate?(.chatTranscriptScreenRequested) switch try XCTUnwrap(receivedEvent) { case .chatTranscriptScreenRequested: @@ -86,20 +94,4 @@ extension SecureConversationsConfirmationViewModelTests { default: XCTFail() } } - - func testReportingAChangeRendersProps() throws { - var receivedEvent: ConfirmationViewModel.DelegateEvent? - - viewModel.delegate = { event in - receivedEvent = event - } - - viewModel.reportChange() - - switch try XCTUnwrap(receivedEvent) { - case .renderProps(_): - XCTAssertTrue(true) - default: XCTFail() - } - } } diff --git a/GliaWidgetsTests/UIKitBased.Failing.swift b/GliaWidgetsTests/UIKitBased.Failing.swift index baf3fa66a..6edfaf70b 100644 --- a/GliaWidgetsTests/UIKitBased.Failing.swift +++ b/GliaWidgetsTests/UIKitBased.Failing.swift @@ -65,6 +65,10 @@ extension UIKitBased.UIDevice { }, isProximityMonitoringEnabled: { _ in fail("\(Self.self).isProximityMonitoringEnabled") + }, + orientationDidChangeNotification: { + fail("\(Self.self).orientationDidChangeNotification") + return NSNotification.Name(rawValue: "") } ) } diff --git a/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift index 134c38231..d96dea1be 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift @@ -7,12 +7,14 @@ final class SecureConversationsConfirmationScreenDynamicTypeFontTests: SnapshotT let theme = Theme.mock() func test_confirmationView_extra3Large() { - let props = Self.makeConfirmationProps(style: theme.secureConversationsConfirmation) - let viewController = SecureConversations.ConfirmationViewController( - viewModel: .init(environment: .init(confirmationStyle: theme.defaultSecureConversationsConfirmationStyle)), - viewFactory: .mock(theme: theme, messageRenderer: nil, environment: .mock), - props: props + let model: SecureConversations.ConfirmationViewSwiftUI.Model = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: theme.defaultSecureConversationsConfirmationStyle, + delegate: nil ) + let viewController = SecureConversations.ConfirmationViewController(model: model) viewController.view.frame = UIScreen.main.bounds assertSnapshot( @@ -21,28 +23,5 @@ final class SecureConversationsConfirmationScreenDynamicTypeFontTests: SnapshotT named: self.nameForDevice() ) } - - // MARK: - Helpers - - static func headerProps() -> Header.Props { - .mock( - title: "Secure Conversations", - backButton: .init(style: .mock(image: Asset.back.image)), - closeButton: .init(style: .mock(image: Asset.close.image)) - ) - } - - static func makeConfirmationProps( - headerProps: Header.Props = headerProps(), - style: SecureConversations.ConfirmationStyle - ) -> SecureConversations.ConfirmationViewController.Props { - .init( - confirmationViewProps: .init( - style: style, - header: headerProps, - checkMessageButtonTap: .nop - ) - ) - } } // swiftlint:enable type_name diff --git a/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift index 41a2645fe..5c42e4233 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift @@ -6,41 +6,20 @@ class SecureConversationsConfirmationScreenLayoutTests: SnapshotTestCase { let theme = Theme.mock() func test_confirmationView() { - let props = Self.makeConfirmationProps(style: theme.secureConversationsConfirmation) - let viewController = SecureConversations.ConfirmationViewController( - viewModel: .init(environment: .init(confirmationStyle: theme.defaultSecureConversationsConfirmationStyle)), - viewFactory: .mock(theme: theme, messageRenderer: nil, environment: .mock), - props: props + let model: SecureConversations.ConfirmationViewSwiftUI.Model = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: theme.defaultSecureConversationsConfirmationStyle, + delegate: nil ) + let viewController = SecureConversations.ConfirmationViewController(model: model) viewController.view.frame = UIScreen.main.bounds assertSnapshot( - matching: viewController.view, + matching: viewController, as: .image, named: self.nameForDevice() ) } - - // MARK: - Helpers - - static func headerProps() -> Header.Props { - .mock( - title: "Secure Conversations", - backButton: .init(style: .mock(image: Asset.back.image)), - closeButton: .init(style: .mock(image: Asset.close.image)) - ) - } - - static func makeConfirmationProps( - headerProps: Header.Props = headerProps(), - style: SecureConversations.ConfirmationStyle - ) -> SecureConversations.ConfirmationViewController.Props { - .init( - confirmationViewProps: .init( - style: style, - header: headerProps, - checkMessageButtonTap: .nop - ) - ) - } } diff --git a/SnapshotTests/SecureConversationsConfirmationScreenTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenTests.swift index 587292207..812d6eab9 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenTests.swift @@ -7,12 +7,14 @@ class SecureConversationsConfirmationScreenTests: SnapshotTestCase { let theme = Theme.mock() func test_confirmationView() { - let props = Self.makeConfirmationProps(style: theme.secureConversationsConfirmation) - let viewController = SecureConversations.ConfirmationViewController( - viewModel: .init(environment: .init(confirmationStyle: theme.defaultSecureConversationsConfirmationStyle)), - viewFactory: .mock(theme: theme, messageRenderer: nil, environment: .mock), - props: props + let model: SecureConversations.ConfirmationViewSwiftUI.Model = .init( + environment: .init( + orientationManager: .mock(), uiApplication: .mock + ), + style: theme.defaultSecureConversationsConfirmationStyle, + delegate: nil ) + let viewController = SecureConversations.ConfirmationViewController(model: model) viewController.view.frame = UIScreen.main.bounds assertSnapshot( @@ -21,27 +23,4 @@ class SecureConversationsConfirmationScreenTests: SnapshotTestCase { named: self.nameForDevice() ) } - - // MARK: - Helpers - - static func headerProps() -> Header.Props { - .mock( - title: "Secure Conversations", - backButton: .init(style: .mock(image: Asset.back.image)), - closeButton: .init(style: .mock(image: Asset.close.image)) - ) - } - - static func makeConfirmationProps( - headerProps: Header.Props = headerProps(), - style: SecureConversations.ConfirmationStyle - ) -> SecureConversations.ConfirmationViewController.Props { - .init( - confirmationViewProps: .init( - style: style, - header: headerProps, - checkMessageButtonTap: .nop - ) - ) - } } From 857913d5040a87b74e3e6a7c643328f73771bb31 Mon Sep 17 00:00:00 2001 From: Igor Kravchenko Date: Fri, 22 Sep 2023 13:16:26 +0300 Subject: [PATCH 06/40] Add missing accessibility identifier and introduce new view modifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After migration to SwiftUI, Secure Conversation’s Confirmation header close button is missing 'header_close_button' identifier, which results in acceptance tests failure. Since we are constrained to iOS 13 deployment target, it made sense to add dedicated view modifier to resolve between depreciated and new methods for providing accessibility identifier to avoid deprecation warnings. This modifier will become obsolete once we bump up deployment target to iOS 14. MOB-2694 --- GliaWidgets.xcodeproj/project.pbxproj | 4 ++++ ...eConversations.ConfirmationViewModel.swift | 2 ++ .../Buttons/HeaderButtonSwiftUI.swift | 6 ++++- .../Extensions/View+Accessibility.swift | 22 +++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 837b163fd..23b2730ce 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -519,6 +519,7 @@ AF10ED8F29BF849A00E85309 /* UnreadMessageDividerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF10ED8E29BF849A00E85309 /* UnreadMessageDividerView.swift */; }; AF10ED9129BF85C700E85309 /* UnreadMessageDividerStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF10ED9029BF85C700E85309 /* UnreadMessageDividerStyle.swift */; }; AF11F30728BE6F0C002ACEB4 /* UIAlertController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF11F30628BE6F0C002ACEB4 /* UIAlertController+Extensions.swift */; }; + AF18F1D52ABD954500121627 /* View+Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF18F1D42ABD954500121627 /* View+Accessibility.swift */; }; AF22C8852A6154780004BF3C /* AlertViewControllerLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF22C8842A6154780004BF3C /* AlertViewControllerLayoutTests.swift */; }; AF22C8872A6182AF0004BF3C /* BubbleViewLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF22C8862A6182AF0004BF3C /* BubbleViewLayoutTests.swift */; }; AF22C8892A6184C50004BF3C /* CallViewControllerLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF22C8882A6184C50004BF3C /* CallViewControllerLayoutTests.swift */; }; @@ -1256,6 +1257,7 @@ AF10ED8E29BF849A00E85309 /* UnreadMessageDividerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadMessageDividerView.swift; sourceTree = ""; }; AF10ED9029BF85C700E85309 /* UnreadMessageDividerStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadMessageDividerStyle.swift; sourceTree = ""; }; AF11F30628BE6F0C002ACEB4 /* UIAlertController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Extensions.swift"; sourceTree = ""; }; + AF18F1D42ABD954500121627 /* View+Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Accessibility.swift"; sourceTree = ""; }; AF22C8842A6154780004BF3C /* AlertViewControllerLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewControllerLayoutTests.swift; sourceTree = ""; }; AF22C8862A6182AF0004BF3C /* BubbleViewLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BubbleViewLayoutTests.swift; sourceTree = ""; }; AF22C8882A6184C50004BF3C /* CallViewControllerLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallViewControllerLayoutTests.swift; sourceTree = ""; }; @@ -3531,6 +3533,7 @@ isa = PBXGroup; children = ( C06152D42AB1BC1300063BF8 /* Font+Extensions.swift */, + AF18F1D42ABD954500121627 /* View+Accessibility.swift */, ); path = Extensions; sourceTree = ""; @@ -4524,6 +4527,7 @@ 845876B1282A9EAF007AC3DF /* CheckboxView.Props.Accessibility.swift in Sources */, 1A4AF5CD25AEF4A0002CD0F4 /* AlertViewController+Message.swift in Sources */, AFCF8A5C2A02AB3000B7ABB3 /* OutgoingMessage.Mock.swift in Sources */, + AF18F1D52ABD954500121627 /* View+Accessibility.swift in Sources */, C0D2F08F29A61A8D00803B47 /* VideoCallViewController.Mock.swift in Sources */, 1A7CA8242574D68E0047CBBE /* ConnectStatusView.swift in Sources */, 845E2F78283E2D4200C04D56 /* PoweredByStyle.swift in Sources */, diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift index 0dac97c78..faadb8390 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewModel.swift @@ -55,12 +55,14 @@ extension SecureConversations.ConfirmationViewSwiftUI.Model { self?.delegate?(.closeTapped) }), style: style.header.closeButton, + accessibilityIdentifier: "header_close_button", isEnabled: true, isHidden: false ) let endScreenShareButtonProps: HeaderButtonSwiftUI.Model = .init( style: style.header.endScreenShareButton, + accessibilityIdentifier: "header_end_screen_sharing_button", isEnabled: false, isHidden: true ) diff --git a/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift index 34e24658d..fd71f847b 100644 --- a/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift +++ b/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift @@ -19,7 +19,8 @@ struct HeaderButtonSwiftUI: View { .accessibility(label: Text(model.style.accessibility.label)) .accessibility(addTraits: .isButton) .accessibility(removeTraits: .isImage) - .onTapGesture(perform: model.tap.callAsFunction) + .onTapGesture(perform: model.tap.execute) + .migrationAccessibilityIdentifier(model.accessibilityIdentifier) } } @@ -27,6 +28,7 @@ extension HeaderButtonSwiftUI { final class Model: ObservableObject { var tap: Cmd var style: HeaderButtonStyle + var accessibilityIdentifier: String var size: CGSize var isEnabled: Bool var isHidden: Bool @@ -34,6 +36,7 @@ extension HeaderButtonSwiftUI { init( tap: Cmd = .nop, style: HeaderButtonStyle, + accessibilityIdentifier: String, size: CGSize = CGSize(width: 14, height: 14), isEnabled: Bool, isHidden: Bool @@ -43,6 +46,7 @@ extension HeaderButtonSwiftUI { self.size = size self.isEnabled = isEnabled self.isHidden = isHidden + self.accessibilityIdentifier = accessibilityIdentifier } } } diff --git a/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift b/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift new file mode 100644 index 000000000..e50c5c34e --- /dev/null +++ b/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift @@ -0,0 +1,22 @@ +import SwiftUI + +/// Accessibility identifier view modifier for resolving between +/// deprecated and new method to specify accessibility identifier. +struct MigrationAccessibilityIdentifierModifier: ViewModifier { + let identifier: String + + func body(content: Content) -> some View { + if #available(iOS 14, *) { + content.accessibilityIdentifier(identifier) + } else { + content.accessibility(identifier: identifier) + } + } +} + +/// Modifier for specifying accessibility identifier for avoiding deprecation warning. +extension View { + func migrationAccessibilityIdentifier(_ identifier: String) -> some View { + self.modifier(MigrationAccessibilityIdentifierModifier(identifier: identifier)) + } +} From d843f0dad9565820a9f907e9e1da8ed14191bc2f Mon Sep 17 00:00:00 2001 From: Egor Egorov Date: Fri, 22 Sep 2023 15:52:00 +0300 Subject: [PATCH 07/40] Bump CoreSDK version to 1.1.3 --- GliaWidgets.podspec | 2 +- Package.swift | 4 ++-- Podfile.lock | 4 ++-- templates/GliaWidgets.podspec | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/GliaWidgets.podspec b/GliaWidgets.podspec index 2deaec595..96244e430 100644 --- a/GliaWidgets.podspec +++ b/GliaWidgets.podspec @@ -19,5 +19,5 @@ Pod::Spec.new do |s| } s.exclude_files = ['GliaWidgets/Window/**'] - s.dependency 'GliaCoreSDK', '1.1.2' + s.dependency 'GliaCoreSDK', '1.1.3' end diff --git a/Package.swift b/Package.swift index ef6d3d39f..ebfe359df 100644 --- a/Package.swift +++ b/Package.swift @@ -35,8 +35,8 @@ let package = Package( ), .binaryTarget( name: "GliaCoreSDK", - url: "https://github.com/salemove/ios-bundle/releases/download/1.1.2/GliaCoreSDK.xcframework.zip", - checksum: "a4b52dd6b930904ee655d3065a1c76eda2546e2e5cad6649826f61843737e31b" + url: "https://github.com/salemove/ios-bundle/releases/download/1.1.3/GliaCoreSDK.xcframework.zip", + checksum: "ffffc1a4bdbf467b076823d604cf8a628c78fd49a7ceda6dd423f569a13c5fa3" ), .binaryTarget( name: "GliaWidgetsXcf", diff --git a/Podfile.lock b/Podfile.lock index bdcb7953f..9d6242913 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -7,7 +7,7 @@ PODS: - AccessibilitySnapshot/Core - SnapshotTesting (~> 1.0) - GliaCoreDependency (1.2) - - GliaCoreSDK (1.1.2): + - GliaCoreSDK (1.1.3): - GliaCoreDependency (= 1.2) - TwilioVoice (= 6.3.1) - WebRTC-lib (= 96.0.0) @@ -34,7 +34,7 @@ SPEC REPOS: SPEC CHECKSUMS: AccessibilitySnapshot: a91e4a69f870188b51f43863d9fc7269d07cdd93 GliaCoreDependency: 87b3897f0d85321ecf77f1faa829211ad527e54d - GliaCoreSDK: 4ba45fcff96ae79480cabf3b871c6932ca18efae + GliaCoreSDK: cae2181c8d19f39609c727a8c2a2268e256f5746 SnapshotTesting: 6141c48b6aa76ead61431ca665c14ab9a066c53b SwiftLint: 13280e21cdda6786ad908dc6e416afe5acd1fcb7 TwilioVoice: 098a959181d4607921f5822d3c9f13043ea4075b diff --git a/templates/GliaWidgets.podspec b/templates/GliaWidgets.podspec index f465dc0fc..9f82b74fb 100644 --- a/templates/GliaWidgets.podspec +++ b/templates/GliaWidgets.podspec @@ -19,5 +19,5 @@ Pod::Spec.new do |s| } s.exclude_files = ['GliaWidgets/Window/**'] - s.dependency 'GliaCoreSDK', '1.1.2' + s.dependency 'GliaCoreSDK', '1.1.3' end From 456b847c49a9d47c5c6cdb47b2753c6a234830ad Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Thu, 21 Sep 2023 14:18:05 +0300 Subject: [PATCH 08/40] Add landscape snapshot tests This PR adds snapshot tests in landscape mode for regular and large font types. MOB-2683 --- .../Public/Glia/Glia+StartEngagement.swift | 2 +- ...gagementCoordinator.Environment.Mock.swift | 2 +- .../EngagementCoordinator.swift | 2 +- .../Glia.Environment.Live.swift | 2 +- .../Glia.Environment.Mock.swift | 2 +- ...rtViewControllerDynamicTypeFontTests.swift | 20 +++++ .../AlertViewControllerLayoutTests.swift | 22 +++++- SnapshotTests/AlertViewControllerTests.swift | 2 +- .../BubbleViewDynamicTypeFontTests.swift | 6 +- SnapshotTests/BubbleViewLayoutTests.swift | 13 +++- SnapshotTests/BubbleViewVoiceOverTests.swift | 3 +- ...llViewControllerDynamicTypeFontTests.swift | 30 ++++++++ .../CallViewControllerLayoutTests.swift | 32 +++++++- .../CallViewControllerVoiceOverTests.swift | 2 +- ...tCallUpgradeViewDynamicTypeFontTests.swift | 10 +++ .../ChatCallUpgradeViewLayoutTests.swift | 12 ++- .../ChatCallUpgradeViewVoiceOverTests.swift | 2 +- ...atViewControllerDynamicTypeFontTests.swift | 22 +++++- .../ChatViewControllerLayoutTests.swift | 46 ++++++++++- .../ChatViewControllerVoiceOverTests.swift | 2 +- ...reViewControllerDynamicTypeFontTests.swift | 5 ++ ...ScreenShareViewControllerLayoutTests.swift | 7 +- .../ScreenShareViewControllerTests.swift | 2 +- ...nfirmationScreenDynamicTypeFontTests.swift | 7 +- ...sationsConfirmationScreenLayoutTests.swift | 9 ++- ...ConversationsConfirmationScreenTests.swift | 2 +- ...onsWelcomeScreenDynamicTypeFontTests.swift | 21 ++++- ...onversationsWelcomeScreenLayoutTests.swift | 23 +++++- ...ecureConversationsWelcomeScreenTests.swift | 2 +- SnapshotTests/SnapshotTestCase.swift | 76 ++++++++++++++++--- ...eyViewControllerDynamicTypeFontTests.swift | 33 +++++++- .../SurveyViewControllerLayoutTests.swift | 35 ++++++++- .../SurveyViewControllerVoiceOverTests.swift | 20 ++++- ...llViewControllerDynamicTypeFontTests.swift | 5 ++ .../VideoCallViewControllerLayoutTests.swift | 7 +- .../VideoCallViewControllerTests.swift | 2 +- ...deViewControllerDynamicTypeFontTests.swift | 30 ++++++++ ...VisitorCodeViewControllerLayoutTests.swift | 32 +++++++- .../VisitorCodeViewControllerTests.swift | 2 +- 39 files changed, 492 insertions(+), 62 deletions(-) diff --git a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift index 6a5ab4f35..55423ccf5 100644 --- a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift +++ b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift @@ -124,7 +124,7 @@ extension Glia { startSocketObservation: environment.coreSdk.startSocketObservation, stopSocketObservation: environment.coreSdk.stopSocketObservation, pushNotifications: environment.coreSdk.pushNotifications, - createSendMessagePayload: environment.coreSdk.createSendMessagePayload, + createSendMessagePayload: environment.coreSdk.createSendMessagePayload, orientationManager: environment.orientationManager ) ) diff --git a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift index 7247c6583..0c297c735 100644 --- a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift +++ b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.Environment.Mock.swift @@ -34,7 +34,7 @@ extension EngagementCoordinator.Environment { startSocketObservation: {}, stopSocketObservation: {}, pushNotifications: .mock, - createSendMessagePayload: { _, _ in .mock() }, + createSendMessagePayload: { _, _ in .mock() }, orientationManager: .mock() ) } diff --git a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift index 6d972ab51..5376ac2f8 100644 --- a/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift +++ b/GliaWidgets/Sources/Coordinators/EngagementCoordinator/EngagementCoordinator.swift @@ -477,7 +477,7 @@ extension EngagementCoordinator { isAuthenticated: environment.isAuthenticated, startSocketObservation: environment.startSocketObservation, stopSocketObservation: environment.stopSocketObservation, - createSendMessagePayload: environment.createSendMessagePayload, + createSendMessagePayload: environment.createSendMessagePayload, orientationManager: environment.orientationManager ) ) diff --git a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift index 72c9717b7..5d96bd07c 100644 --- a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift +++ b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Live.swift @@ -27,7 +27,7 @@ extension Glia.Environment { createFileUploader: FileUploader.init(maximumUploads:environment:), createFileUploadListModel: SecureConversations.FileUploadListViewModel.init, screenShareHandler: ScreenShareHandler.create(), - messagesWithUnreadCountLoaderScheduler: CoreSdkClient.ReactiveSwift.QueueScheduler.main, + messagesWithUnreadCountLoaderScheduler: CoreSdkClient.ReactiveSwift.QueueScheduler.main, orientationManager: .init(environment: .init( uiApplication: .live, uiDevice: .live, diff --git a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift index 013108965..c4d11734d 100644 --- a/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift +++ b/GliaWidgets/Sources/GliaEnvironment/Glia.Environment.Mock.swift @@ -25,7 +25,7 @@ extension Glia.Environment { createFileUploader: FileUploader.mock, createFileUploadListModel: SecureConversations.FileUploadListViewModel.mock(environment:), screenShareHandler: .mock, - messagesWithUnreadCountLoaderScheduler: CoreSdkClient.reactiveSwiftDateSchedulerMock, + messagesWithUnreadCountLoaderScheduler: CoreSdkClient.reactiveSwiftDateSchedulerMock, orientationManager: .mock() ) } diff --git a/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift b/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift index ab1ab191e..eb9ea34a0 100644 --- a/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift @@ -15,6 +15,11 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_mediaUpgradeOffer_extra3Large() { @@ -28,6 +33,11 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_messageAlert_extra3Large() { @@ -41,6 +51,11 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_singleAction_extra3Large() { @@ -54,6 +69,11 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } private func alert(ofKind kind: AlertViewController.Kind) -> AlertViewController { diff --git a/SnapshotTests/AlertViewControllerLayoutTests.swift b/SnapshotTests/AlertViewControllerLayoutTests.swift index df8c9861d..390a08cc2 100644 --- a/SnapshotTests/AlertViewControllerLayoutTests.swift +++ b/SnapshotTests/AlertViewControllerLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class AlertViewControllerLayoutTests: SnapshotTestCase { +final class AlertViewControllerLayoutTests: SnapshotTestCase { func test_screenSharingOffer() { let alert = alert(ofKind: .screenShareOffer( .mock(), @@ -14,6 +14,11 @@ class AlertViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_mediaUpgradeOffer() { @@ -27,6 +32,11 @@ class AlertViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_messageAlert() { @@ -40,6 +50,11 @@ class AlertViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_singleAction() { @@ -53,6 +68,11 @@ class AlertViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: alert, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } private func alert(ofKind kind: AlertViewController.Kind) -> AlertViewController { diff --git a/SnapshotTests/AlertViewControllerTests.swift b/SnapshotTests/AlertViewControllerTests.swift index 31e7e6c9b..0522cb041 100644 --- a/SnapshotTests/AlertViewControllerTests.swift +++ b/SnapshotTests/AlertViewControllerTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class AlertViewControllerTests: SnapshotTestCase { +final class AlertViewControllerTests: SnapshotTestCase { func test_screenSharingOffer() { let alert = alert(ofKind: .screenShareOffer( .mock(), diff --git a/SnapshotTests/BubbleViewDynamicTypeFontTests.swift b/SnapshotTests/BubbleViewDynamicTypeFontTests.swift index cb60ee7d2..e3f65d375 100644 --- a/SnapshotTests/BubbleViewDynamicTypeFontTests.swift +++ b/SnapshotTests/BubbleViewDynamicTypeFontTests.swift @@ -7,10 +7,14 @@ final class BubbleViewDynamicTypeFontTests: SnapshotTestCase { func test_bubble_extra3Large() { let bubble = ViewFactory.mock().makeBubbleView() bubble.frame = .init(origin: .zero, size: .init(width: 50, height: 50)) - // If shadow will cause failing test locally or on CI, we should disable it. assertSnapshot( matching: bubble, as: .extra3LargeFontStrategy ) + assertSnapshot( + matching: bubble, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/BubbleViewLayoutTests.swift b/SnapshotTests/BubbleViewLayoutTests.swift index 47538040f..d3237b534 100644 --- a/SnapshotTests/BubbleViewLayoutTests.swift +++ b/SnapshotTests/BubbleViewLayoutTests.swift @@ -2,11 +2,18 @@ import SnapshotTesting import XCTest -class BubbleViewLayoutTests: SnapshotTestCase { +final class BubbleViewLayoutTests: SnapshotTestCase { func test_bubble() { let bubble = ViewFactory.mock().makeBubbleView() bubble.frame = .init(origin: .zero, size: .init(width: 50, height: 50)) - // If shadow will cause failing test locally or on CI, we should disable it. - assertSnapshot(matching: bubble, as: .image) + assertSnapshot( + matching: bubble, + as: .image + ) + assertSnapshot( + matching: bubble, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/BubbleViewVoiceOverTests.swift b/SnapshotTests/BubbleViewVoiceOverTests.swift index c9b99f7ab..6214c5e43 100644 --- a/SnapshotTests/BubbleViewVoiceOverTests.swift +++ b/SnapshotTests/BubbleViewVoiceOverTests.swift @@ -3,11 +3,10 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class BubbleViewVoiceOverTests: SnapshotTestCase { +final class BubbleViewVoiceOverTests: SnapshotTestCase { func test_bubble() { let bubble = ViewFactory.mock().makeBubbleView() bubble.frame = .init(origin: .zero, size: .init(width: 50, height: 50)) - // If shadow will cause failing test locally or on CI, we should disable it. assertSnapshot(matching: bubble, as: .accessibilityImage(precision: SnapshotTestCase.possiblePrecision)) } } diff --git a/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift b/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift index eb7ff9b11..6498c88ea 100644 --- a/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift @@ -11,6 +11,11 @@ final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_audioCallConnectingState_extra3Large() throws { @@ -21,6 +26,11 @@ final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_audioCallConnectedState_extra3Large() throws { @@ -31,6 +41,11 @@ final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_mockVideoCallConnectingState_extra3Large() throws { @@ -41,6 +56,11 @@ final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_mockVideoCallQueueState_extra3Large() throws { @@ -51,6 +71,11 @@ final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_mockVideoCallConnectedState_extra3Large() throws { @@ -61,5 +86,10 @@ final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/CallViewControllerLayoutTests.swift b/SnapshotTests/CallViewControllerLayoutTests.swift index 2093dec4d..7ad4f789a 100644 --- a/SnapshotTests/CallViewControllerLayoutTests.swift +++ b/SnapshotTests/CallViewControllerLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class CallViewControllerLayoutTests: SnapshotTestCase { +final class CallViewControllerLayoutTests: SnapshotTestCase { func test_audioCallQueueState() throws { let viewController = try CallViewController.mockAudioCallQueueState() viewController.view.frame = UIScreen.main.bounds @@ -11,6 +11,11 @@ class CallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_audioCallConnectingState() throws { @@ -21,6 +26,11 @@ class CallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_audioCallConnectedState() throws { @@ -31,6 +41,11 @@ class CallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_mockVideoCallConnectingState() throws { @@ -41,6 +56,11 @@ class CallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_mockVideoCallQueueState() throws { @@ -51,6 +71,11 @@ class CallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_mockVideoCallConnectedState() throws { @@ -61,5 +86,10 @@ class CallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/CallViewControllerVoiceOverTests.swift b/SnapshotTests/CallViewControllerVoiceOverTests.swift index 316dbb008..e6a365781 100644 --- a/SnapshotTests/CallViewControllerVoiceOverTests.swift +++ b/SnapshotTests/CallViewControllerVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class CallViewControllerVoiceOverTests: SnapshotTestCase { +final class CallViewControllerVoiceOverTests: SnapshotTestCase { func test_audioCallQueueState() throws { let viewController = try CallViewController.mockAudioCallQueueState() viewController.view.frame = UIScreen.main.bounds diff --git a/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift b/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift index d7dd5efaa..295477e13 100644 --- a/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift +++ b/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift @@ -10,6 +10,11 @@ final class ChatCallUpgradeViewDynamicTypeFontTests: SnapshotTestCase { matching: upgradeView, as: .extra3LargeFontStrategy ) + assertSnapshot( + matching: upgradeView, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_chatCallUpgradeViewToVideo_extra3Large() { @@ -19,5 +24,10 @@ final class ChatCallUpgradeViewDynamicTypeFontTests: SnapshotTestCase { matching: upgradeView, as: .extra3LargeFontStrategy ) + assertSnapshot( + matching: upgradeView, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift b/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift index e9d4a210e..da552c62b 100644 --- a/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift +++ b/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class ChatCallUpgradeViewLayoutTests: SnapshotTestCase { +final class ChatCallUpgradeViewLayoutTests: SnapshotTestCase { func test_chatCallUpgradeViewToAudio() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.audioUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 120)) @@ -10,6 +10,11 @@ class ChatCallUpgradeViewLayoutTests: SnapshotTestCase { matching: upgradeView, as: .image ) + assertSnapshot( + matching: upgradeView, + as: .image, + named: nameForDevice(.landscape) + ) } func test_chatCallUpgradeViewToVideo() { @@ -19,5 +24,10 @@ class ChatCallUpgradeViewLayoutTests: SnapshotTestCase { matching: upgradeView, as: .image ) + assertSnapshot( + matching: upgradeView, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift b/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift index 34110d6c2..5dd76d736 100644 --- a/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift +++ b/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class ChatCallUpgradeViewVoiceOverTests: SnapshotTestCase { +final class ChatCallUpgradeViewVoiceOverTests: SnapshotTestCase { func test_chatCallUpgradeViewToAudio() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.audioUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 120)) diff --git a/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift b/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift index e502d74c0..c694b1d81 100644 --- a/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift @@ -11,6 +11,11 @@ final class ChatViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_visitorUploadedFileStates_extra3Large() throws { @@ -21,6 +26,11 @@ final class ChatViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_choiceCard_extra3Large() throws { @@ -31,6 +41,11 @@ final class ChatViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_visitorFileDownloadStates_extra3Large() throws { @@ -49,7 +64,12 @@ final class ChatViewControllerDynamicTypeFontTests: SnapshotTestCase { assertSnapshot( matching: viewController, as: .extra3LargeFontStrategy, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) ) } } diff --git a/SnapshotTests/ChatViewControllerLayoutTests.swift b/SnapshotTests/ChatViewControllerLayoutTests.swift index 6b8a371b4..cfb016713 100644 --- a/SnapshotTests/ChatViewControllerLayoutTests.swift +++ b/SnapshotTests/ChatViewControllerLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class ChatViewControllerLayoutTests: SnapshotTestCase { +final class ChatViewControllerLayoutTests: SnapshotTestCase { func test_messagesFromHistory() { let viewController = ChatViewController.mockHistoryMessagesScreen() viewController.view.frame = UIScreen.main.bounds @@ -11,6 +11,11 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_visitorUploadedFileStates() throws { @@ -21,6 +26,11 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_choiceCard() throws { @@ -31,6 +41,11 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_gvaPersistentButton() throws { @@ -41,6 +56,11 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_gvaResponseText() throws { @@ -51,6 +71,11 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_gvaGalleryCard() throws { @@ -61,6 +86,11 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_gvaQuickReply() throws { @@ -79,7 +109,12 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { assertSnapshot( matching: view, as: .image, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: view, + as: .imageLandscape, + named: nameForDevice(.landscape) ) } @@ -99,7 +134,12 @@ class ChatViewControllerLayoutTests: SnapshotTestCase { assertSnapshot( matching: viewController, as: .image, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) ) } } diff --git a/SnapshotTests/ChatViewControllerVoiceOverTests.swift b/SnapshotTests/ChatViewControllerVoiceOverTests.swift index d41d9457b..40fa87f20 100644 --- a/SnapshotTests/ChatViewControllerVoiceOverTests.swift +++ b/SnapshotTests/ChatViewControllerVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class ChatViewControllerVoiceOverTests: SnapshotTestCase { +final class ChatViewControllerVoiceOverTests: SnapshotTestCase { func test_messagesFromHistory() { let viewController = ChatViewController.mockHistoryMessagesScreen() viewController.view.frame = UIScreen.main.bounds diff --git a/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift b/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift index efdbee770..88ebc2db7 100644 --- a/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift @@ -28,6 +28,11 @@ final class ScreenShareViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: screenShareViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } // swiftlint:enable type_name diff --git a/SnapshotTests/ScreenShareViewControllerLayoutTests.swift b/SnapshotTests/ScreenShareViewControllerLayoutTests.swift index 3cdb38c4c..857fe9128 100644 --- a/SnapshotTests/ScreenShareViewControllerLayoutTests.swift +++ b/SnapshotTests/ScreenShareViewControllerLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class ScreenShareViewControllerLayoutTests: SnapshotTestCase { +final class ScreenShareViewControllerLayoutTests: SnapshotTestCase { func testScreenShareViewController() { let theme = Theme() let font = theme.font @@ -27,5 +27,10 @@ class ScreenShareViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: screenShareViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/ScreenShareViewControllerTests.swift b/SnapshotTests/ScreenShareViewControllerTests.swift index 5e9dd973c..319343539 100644 --- a/SnapshotTests/ScreenShareViewControllerTests.swift +++ b/SnapshotTests/ScreenShareViewControllerTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class ScreenShareViewControllerTests: SnapshotTestCase { +final class ScreenShareViewControllerTests: SnapshotTestCase { func testScreenShareViewController() { let theme = Theme() let font = theme.font diff --git a/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift index d96dea1be..a81d37442 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift @@ -20,7 +20,12 @@ final class SecureConversationsConfirmationScreenDynamicTypeFontTests: SnapshotT assertSnapshot( matching: viewController.view, as: .extra3LargeFontStrategy, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) ) } } diff --git a/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift index 5c42e4233..87c7ac6db 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class SecureConversationsConfirmationScreenLayoutTests: SnapshotTestCase { +final class SecureConversationsConfirmationScreenLayoutTests: SnapshotTestCase { let theme = Theme.mock() func test_confirmationView() { @@ -19,7 +19,12 @@ class SecureConversationsConfirmationScreenLayoutTests: SnapshotTestCase { assertSnapshot( matching: viewController, as: .image, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) ) } } diff --git a/SnapshotTests/SecureConversationsConfirmationScreenTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenTests.swift index 812d6eab9..2a144d8b3 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class SecureConversationsConfirmationScreenTests: SnapshotTestCase { +final class SecureConversationsConfirmationScreenTests: SnapshotTestCase { let theme = Theme.mock() func test_confirmationView() { diff --git a/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift b/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift index 5bd896ffc..59f707f78 100644 --- a/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift +++ b/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift @@ -21,7 +21,12 @@ final class SecureConversationsWelcomeScreenDynamicTypeFontTests: SnapshotTestCa assertSnapshot( matching: viewController.view, as: .extra3LargeFontStrategy, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) ) } @@ -43,7 +48,12 @@ final class SecureConversationsWelcomeScreenDynamicTypeFontTests: SnapshotTestCa assertSnapshot( matching: viewController.view, as: .extra3LargeFontStrategy, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) ) } @@ -59,7 +69,12 @@ final class SecureConversationsWelcomeScreenDynamicTypeFontTests: SnapshotTestCa assertSnapshot( matching: viewController.view, as: .extra3LargeFontStrategy, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) ) } diff --git a/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift b/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift index fa8beb3b8..6c3d40a32 100644 --- a/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift +++ b/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { +final class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { let theme = Theme.mock() func test_welcomeView() { @@ -20,7 +20,12 @@ class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { assertSnapshot( matching: viewController.view, as: .image, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .imageLandscape, + named: nameForDevice(.landscape) ) } @@ -42,7 +47,12 @@ class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { assertSnapshot( matching: viewController.view, as: .image, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .imageLandscape, + named: nameForDevice(.landscape) ) } @@ -58,7 +68,12 @@ class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { assertSnapshot( matching: viewController.view, as: .image, - named: self.nameForDevice() + named: nameForDevice() + ) + assertSnapshot( + matching: viewController.view, + as: .imageLandscape, + named: nameForDevice(.landscape) ) } diff --git a/SnapshotTests/SecureConversationsWelcomeScreenTests.swift b/SnapshotTests/SecureConversationsWelcomeScreenTests.swift index ec485af2f..4d97ae2c6 100644 --- a/SnapshotTests/SecureConversationsWelcomeScreenTests.swift +++ b/SnapshotTests/SecureConversationsWelcomeScreenTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class SecureConversationsWelcomeScreenTests: SnapshotTestCase { +final class SecureConversationsWelcomeScreenTests: SnapshotTestCase { let theme = Theme.mock() func test_welcomeView() { diff --git a/SnapshotTests/SnapshotTestCase.swift b/SnapshotTests/SnapshotTestCase.swift index 92050d2e8..126549834 100644 --- a/SnapshotTests/SnapshotTestCase.swift +++ b/SnapshotTests/SnapshotTestCase.swift @@ -50,15 +50,46 @@ extension SnapshotTestCase { } } - func nameForDevice(baseName: String? = nil) -> String { + /// This method sets the name for the snapshot tests by taking one parameter. + /// Depending of the case passed in, either prefix, suffix, or nothing + /// additional will be added to the the base name. The method returns a string. + func nameForDevice(_ baseName: NameForDevice = .portrait) -> String { let size = UIScreen.main.bounds.size let scale = UIScreen.main.scale let version = UIDevice.current.systemVersion let deviceName = "\(Int(size.width))x\(Int(size.height))-\(version)-\(Int(scale))x" - return [baseName, deviceName] - .compactMap { $0 } - .joined(separator: "-") + switch baseName { + case let .baseName(value): + return [value, deviceName] + .compactMap { $0 } + .joined(separator: "-") + case .portrait: + return "\(deviceName)" + case .landscape: + return "\(deviceName)-landscape" + } + } + + /// All available cases for the snapshot tests name. This Enum + /// conforms to ExpressibleByStringLiteral allowing a string to be + /// passed instead of a case, that will convert it to baseName case. + /// + /// - baseName(String?) case is a string that can be added as prefix + /// to the test name + /// + /// - portrait case serves as a default case for snapshot tests and + /// won't add anything additional to the name + /// + /// - landscape case will add suffix to the end of the name + enum NameForDevice: ExpressibleByStringLiteral { + case baseName(String?) + case portrait + case landscape + + init(stringLiteral value: String) { + self = .baseName(value) + } } } @@ -188,16 +219,32 @@ extension Snapshotting where Value == UIView, Format == UIImage { ) ) } -} -extension Snapshotting where Value == UIViewController, Format == UIImage { + static var extra3LargeFontStrategyLandscape: Self { + let traits = UITraitCollection(traitsFrom: [ + .init(preferredContentSizeCategory: .accessibilityExtraExtraExtraLarge) + ] + commonTraitCollection) + + return Self.image(traits: traits) + } + + static var imageLandscape: Self { + let traits = UITraitCollection(traitsFrom: [ + .init(preferredContentSizeCategory: .medium), + ] + commonTraitCollection) + + return Self.image(traits: traits) + } + private static var commonTraitCollection: [UITraitCollection] = [ - .init(layoutDirection: .leftToRight), - .init(userInterfaceIdiom: .phone), - .init(horizontalSizeClass: .regular), - .init(verticalSizeClass: .compact), - ] + .init(layoutDirection: .leftToRight), + .init(userInterfaceIdiom: .phone), + .init(horizontalSizeClass: .regular), + .init(verticalSizeClass: .compact), + ] +} +extension Snapshotting where Value == UIViewController, Format == UIImage { static var extra3LargeFontStrategyLandscape: Self { let traits = UITraitCollection(traitsFrom: [ .init(preferredContentSizeCategory: .accessibilityExtraExtraExtraLarge) @@ -219,4 +266,11 @@ extension Snapshotting where Value == UIViewController, Format == UIImage { return Self.image(on: viewImageConfig) } + + private static var commonTraitCollection: [UITraitCollection] = [ + .init(layoutDirection: .leftToRight), + .init(userInterfaceIdiom: .phone), + .init(horizontalSizeClass: .regular), + .init(verticalSizeClass: .compact), + ] } diff --git a/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift b/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift index 2e7fe033a..37f98c751 100644 --- a/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift @@ -4,32 +4,59 @@ import XCTest final class SurveyViewControllerDynamicTypeFontTests: SnapshotTestCase { func test_emptySurvey_extra3Large() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .emptyPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .emptyPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_filledSurvey_extra3Large() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .filledPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .filledPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func test_emptySurveyErrorState_extra3Large() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .errorPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .errorPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/SurveyViewControllerLayoutTests.swift b/SnapshotTests/SurveyViewControllerLayoutTests.swift index 17ca7fd41..23961a2c2 100644 --- a/SnapshotTests/SurveyViewControllerLayoutTests.swift +++ b/SnapshotTests/SurveyViewControllerLayoutTests.swift @@ -2,34 +2,61 @@ import SnapshotTesting import XCTest -class SurveyViewControllerLayoutTests: SnapshotTestCase { +final class SurveyViewControllerLayoutTests: SnapshotTestCase { func test_emptySurvey() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .emptyPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .emptyPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_filledSurvey() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .filledPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .filledPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func test_emptySurveyErrorState() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .errorPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .errorPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, as: .image, named: nameForDevice() ) + assertSnapshot( + matching: viewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/SurveyViewControllerVoiceOverTests.swift b/SnapshotTests/SurveyViewControllerVoiceOverTests.swift index e66ee3071..4d06d1def 100644 --- a/SnapshotTests/SurveyViewControllerVoiceOverTests.swift +++ b/SnapshotTests/SurveyViewControllerVoiceOverTests.swift @@ -3,9 +3,13 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class SurveyViewControllerVoiceOverTests: SnapshotTestCase { +final class SurveyViewControllerVoiceOverTests: SnapshotTestCase { func test_emptySurvey() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .emptyPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .emptyPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, @@ -15,7 +19,11 @@ class SurveyViewControllerVoiceOverTests: SnapshotTestCase { } func test_filledSurvey() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .filledPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .filledPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, @@ -25,7 +33,11 @@ class SurveyViewControllerVoiceOverTests: SnapshotTestCase { } func test_emptySurveyErrorState() { - let viewController = Survey.ViewController(viewFactory: .mock(), environment: .init(notificationCenter: .mock), props: .errorPropsMock()) + let viewController = Survey.ViewController( + viewFactory: .mock(), + environment: .init(notificationCenter: .mock), + props: .errorPropsMock() + ) viewController.view.frame = UIScreen.main.bounds assertSnapshot( matching: viewController, diff --git a/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift b/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift index f9da12752..aa0b8b9bc 100644 --- a/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift @@ -56,6 +56,11 @@ final class VideoCallViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: videoCallViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } // swiftlint:enable type_name diff --git a/SnapshotTests/VideoCallViewControllerLayoutTests.swift b/SnapshotTests/VideoCallViewControllerLayoutTests.swift index a535999f7..f49b05fda 100644 --- a/SnapshotTests/VideoCallViewControllerLayoutTests.swift +++ b/SnapshotTests/VideoCallViewControllerLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class VideoCallViewControllerLayoutTests: SnapshotTestCase { +final class VideoCallViewControllerLayoutTests: SnapshotTestCase { func testVideoCallViewController() { let videoCallViewProps: CallVisualizer.VideoCallView.Props = .mock( buttonBarProps: .mock( @@ -55,5 +55,10 @@ class VideoCallViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: videoCallViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/VideoCallViewControllerTests.swift b/SnapshotTests/VideoCallViewControllerTests.swift index 6ca8ed446..a0c19b532 100644 --- a/SnapshotTests/VideoCallViewControllerTests.swift +++ b/SnapshotTests/VideoCallViewControllerTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class VideoCallViewControllerTests: SnapshotTestCase { +final class VideoCallViewControllerTests: SnapshotTestCase { func testVideoCallViewController() { let videoCallViewProps: CallVisualizer.VideoCallView.Props = .mock( buttonBarProps: .mock( diff --git a/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift b/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift index accde95a0..14a1bcbe1 100644 --- a/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift @@ -19,6 +19,11 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeAlertWhenError() { @@ -36,6 +41,11 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeAlertWhenSuccess() { @@ -53,6 +63,11 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeEmbeddedWhenLoading() { @@ -70,6 +85,11 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeEmbeddedWhenError() { @@ -87,6 +107,11 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeEmbeddedWhenSuccess() { let props: CallVisualizer.VisitorCodeViewController.Props = .init( @@ -103,6 +128,11 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { as: .extra3LargeFontStrategy, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .extra3LargeFontStrategyLandscape, + named: nameForDevice(.landscape) + ) } } // swiftlint:enable type_name diff --git a/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift b/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift index ddf554e06..0ce24ebfa 100644 --- a/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift +++ b/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift @@ -2,7 +2,7 @@ import SnapshotTesting import XCTest -class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { +final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { func testVisitorCodeAlertWhenLoading() { let props: CallVisualizer.VisitorCodeViewController.Props = .init( visitorCodeViewProps: .init( @@ -18,6 +18,11 @@ class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { as: .image, named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeAlertWhenError() { @@ -35,6 +40,11 @@ class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { as: .accessibilityImage(precision: Self.possiblePrecision), named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeAlertWhenSuccess() { @@ -52,6 +62,11 @@ class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { as: .accessibilityImage(precision: Self.possiblePrecision), named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeEmbeddedWhenLoading() { @@ -69,6 +84,11 @@ class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { as: .accessibilityImage(precision: Self.possiblePrecision), named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeEmbeddedWhenError() { @@ -86,6 +106,11 @@ class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { as: .accessibilityImage(precision: Self.possiblePrecision), named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } func testVisitorCodeEmbeddedWhenSuccess() { let props: CallVisualizer.VisitorCodeViewController.Props = .init( @@ -102,5 +127,10 @@ class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { as: .accessibilityImage(precision: Self.possiblePrecision), named: nameForDevice() ) + assertSnapshot( + matching: visitorCodeViewController, + as: .imageLandscape, + named: nameForDevice(.landscape) + ) } } diff --git a/SnapshotTests/VisitorCodeViewControllerTests.swift b/SnapshotTests/VisitorCodeViewControllerTests.swift index fe71f8a6a..da52ad845 100644 --- a/SnapshotTests/VisitorCodeViewControllerTests.swift +++ b/SnapshotTests/VisitorCodeViewControllerTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -class VisitorCodeViewControllerTests: SnapshotTestCase { +final class VisitorCodeViewControllerTests: SnapshotTestCase { func testVisitorCodeAlertWhenLoading() { let props: CallVisualizer.VisitorCodeViewController.Props = .init( visitorCodeViewProps: .init( From 8798a0aa897a407379b5b813da6a034688328f3f Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Mon, 25 Sep 2023 16:01:34 +0300 Subject: [PATCH 09/40] Improve snapshot test This PR improves the way snapshot tests are executed. By creating an extension to UIViewController, we can now create snapshot tests with less code, time, and effort. And, it is much more readable. Since our usages of snapshot tests are very limited (for now), this approach serves those purposes very well. As this proposal is up for debate, I would like to hear everybody's input on it. Please share what are your thoughts on making this change. MOB-2696 --- GliaWidgets.xcodeproj/project.pbxproj | 62 ++++++---- ...rtViewControllerDynamicTypeFontTests.swift | 49 ++------ .../AlertViewControllerLayoutTests.swift | 49 ++------ ...> AlertViewControllerVoiceOverTests.swift} | 27 +---- .../BubbleViewDynamicTypeFontTests.swift | 11 +- SnapshotTests/BubbleViewLayoutTests.swift | 11 +- SnapshotTests/BubbleViewVoiceOverTests.swift | 2 +- SnapshotTests/BubbleWindowLayoutTests.swift | 3 +- ...llViewControllerDynamicTypeFontTests.swift | 78 ++----------- .../CallViewControllerLayoutTests.swift | 78 ++----------- .../CallViewControllerVoiceOverTests.swift | 42 +------ ...tCallUpgradeViewDynamicTypeFontTests.swift | 22 +--- .../ChatCallUpgradeViewLayoutTests.swift | 22 +--- .../ChatCallUpgradeViewVoiceOverTests.swift | 10 +- ...atViewControllerDynamicTypeFontTests.swift | 51 ++------- .../ChatViewControllerLayoutTests.swift | 102 +++-------------- .../ChatViewControllerVoiceOverTests.swift | 54 ++------- ...reViewControllerDynamicTypeFontTests.swift | 14 +-- ...ScreenShareViewControllerLayoutTests.swift | 14 +-- ...enShareViewControllerVoiceOverTests.swift} | 10 +- ...nfirmationScreenDynamicTypeFontTests.swift | 14 +-- ...sationsConfirmationScreenLayoutTests.swift | 14 +-- ...onsConfirmationScreenVoiceOverTests.swift} | 10 +- ...onsWelcomeScreenDynamicTypeFontTests.swift | 42 +------ ...onversationsWelcomeScreenLayoutTests.swift | 42 +------ ...rsationsWelcomeScreenVoiceOverTests.swift} | 26 +---- ...eyViewControllerDynamicTypeFontTests.swift | 39 +------ .../SurveyViewControllerLayoutTests.swift | 39 +------ .../SurveyViewControllerVoiceOverTests.swift | 21 +--- ...llViewControllerDynamicTypeFontTests.swift | 16 +-- .../VideoCallViewControllerLayoutTests.swift | 16 +-- ...deoCallViewControllerVoiceOverTests.swift} | 12 +- ...deViewControllerDynamicTypeFontTests.swift | 96 +++------------- ...VisitorCodeViewControllerLayoutTests.swift | 96 +++------------- .../VisitorCodeViewControllerTests.swift | 107 ------------------ ...itorCodeViewControllerVoiceOverTests.swift | 71 ++++++++++++ .../extensions/UIView+Extensions.swift | 66 +++++++++++ .../UIViewController+Extensions.swift | 68 +++++++++++ 38 files changed, 433 insertions(+), 1073 deletions(-) rename SnapshotTests/{AlertViewControllerTests.swift => AlertViewControllerVoiceOverTests.swift} (58%) rename SnapshotTests/{ScreenShareViewControllerTests.swift => ScreenShareViewControllerVoiceOverTests.swift} (73%) rename SnapshotTests/{SecureConversationsConfirmationScreenTests.swift => SecureConversationsConfirmationScreenVoiceOverTests.swift} (63%) rename SnapshotTests/{SecureConversationsWelcomeScreenTests.swift => SecureConversationsWelcomeScreenVoiceOverTests.swift} (82%) rename SnapshotTests/{VideoCallViewControllerTests.swift => VideoCallViewControllerVoiceOverTests.swift} (84%) delete mode 100644 SnapshotTests/VisitorCodeViewControllerTests.swift create mode 100644 SnapshotTests/VisitorCodeViewControllerVoiceOverTests.swift create mode 100644 SnapshotTests/extensions/UIView+Extensions.swift create mode 100644 SnapshotTests/extensions/UIViewController+Extensions.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 23b2730ce..8662c0858 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -296,8 +296,8 @@ 75C48498299AC71F003EC223 /* Header+Playbook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C48497299AC71F003EC223 /* Header+Playbook.swift */; }; 75CF8D6129B3F1E400CB1524 /* Configuration+Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CF8D6029B3F1E400CB1524 /* Configuration+Mock.swift */; }; 75CF8D6329B7DD8300CB1524 /* SecureConversations+ConfirmationStyle+RemoteConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CF8D6229B7DD8300CB1524 /* SecureConversations+ConfirmationStyle+RemoteConfig.swift */; }; - 75CF8D9129C3A85C00CB1524 /* SecureConversationsWelcomeScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CF8D9029C3A85C00CB1524 /* SecureConversationsWelcomeScreenTests.swift */; }; - 75CF8DAD29C8F2B500CB1524 /* SecureConversationsConfirmationScreenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CF8DAC29C8F2B500CB1524 /* SecureConversationsConfirmationScreenTests.swift */; }; + 75CF8D9129C3A85C00CB1524 /* SecureConversationsWelcomeScreenVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CF8D9029C3A85C00CB1524 /* SecureConversationsWelcomeScreenVoiceOverTests.swift */; }; + 75CF8DAD29C8F2B500CB1524 /* SecureConversationsConfirmationScreenVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CF8DAC29C8F2B500CB1524 /* SecureConversationsConfirmationScreenVoiceOverTests.swift */; }; 75F58EE127E7D5300065BA2D /* Survey.ViewController.Props.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F58EE027E7D5300065BA2D /* Survey.ViewController.Props.swift */; }; 75FF151427F3A2D600FE7BE2 /* Theme+Survey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75FF151327F3A2D600FE7BE2 /* Theme+Survey.swift */; }; 75FF151727F4E13900FE7BE2 /* Theme.Survey.BooleanQuestion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75FF151627F4E13900FE7BE2 /* Theme.Survey.BooleanQuestion.swift */; }; @@ -368,7 +368,7 @@ 846A5C3E29D1C7B00049B29F /* CallVisualizerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A5C3D29D1C7B00049B29F /* CallVisualizerTests.swift */; }; 846A5C4029ED83C50049B29F /* CallVisualizer.Coordinator.DelegateEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A5C3F29ED83C50049B29F /* CallVisualizer.Coordinator.DelegateEvent.swift */; }; 846A5C4529F6BEFA0049B29F /* GliaTests+StartEngagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A5C4429F6BEFA0049B29F /* GliaTests+StartEngagement.swift */; }; - 846E822828996A5C008EFBF0 /* AlertViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E822728996A5C008EFBF0 /* AlertViewControllerTests.swift */; }; + 846E822828996A5C008EFBF0 /* AlertViewControllerVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E822728996A5C008EFBF0 /* AlertViewControllerVoiceOverTests.swift */; }; 847A7643285A1914004044D1 /* FileUploadListViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847A7642285A1914004044D1 /* FileUploadListViewModelTests.swift */; }; 8491AF002A6FB44200CC3E72 /* GvaGalleryCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491AEFF2A6FB44200CC3E72 /* GvaGalleryCardCell.swift */; }; 8491AF022A6FBBBA00CC3E72 /* GvaGalleryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491AF012A6FBBBA00CC3E72 /* GvaGalleryListView.swift */; }; @@ -599,13 +599,15 @@ 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 */; }; + 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 */; }; C07FA04329AF551D00E9FB7F /* ScreenSharingView.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */; }; C07FA04629AF560A00E9FB7F /* ScreenSharingViewController.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */; }; C07FA04B29AF83B900E9FB7F /* ActionButton.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */; }; - C07FA04F29B0E41A00E9FB7F /* ScreenShareViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerTests.swift */; }; - C07FA05029B0E41A00E9FB7F /* VideoCallViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerTests.swift */; }; - C07FA05129B0E41A00E9FB7F /* VisitorCodeViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04E29B0E41A00E9FB7F /* VisitorCodeViewControllerTests.swift */; }; + C07FA04F29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift */; }; + C07FA05029B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift */; }; + C07FA05129B0E41A00E9FB7F /* VisitorCodeViewControllerVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04E29B0E41A00E9FB7F /* VisitorCodeViewControllerVoiceOverTests.swift */; }; C0857DE528D470C1008D171D /* Theme+Shadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0857DE428D470C1008D171D /* Theme+Shadow.swift */; }; C0857DE728D470F2008D171D /* Theme+Layer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0857DE628D470F2008D171D /* Theme+Layer.swift */; }; C0857DEB28D482D0008D171D /* Theme+Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0857DEA28D482D0008D171D /* Theme+Button.swift */; }; @@ -1028,8 +1030,8 @@ 75C48497299AC71F003EC223 /* Header+Playbook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Header+Playbook.swift"; sourceTree = ""; }; 75CF8D6029B3F1E400CB1524 /* Configuration+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Configuration+Mock.swift"; sourceTree = ""; }; 75CF8D6229B7DD8300CB1524 /* SecureConversations+ConfirmationStyle+RemoteConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SecureConversations+ConfirmationStyle+RemoteConfig.swift"; sourceTree = ""; }; - 75CF8D9029C3A85C00CB1524 /* SecureConversationsWelcomeScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversationsWelcomeScreenTests.swift; sourceTree = ""; }; - 75CF8DAC29C8F2B500CB1524 /* SecureConversationsConfirmationScreenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversationsConfirmationScreenTests.swift; sourceTree = ""; }; + 75CF8D9029C3A85C00CB1524 /* SecureConversationsWelcomeScreenVoiceOverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversationsWelcomeScreenVoiceOverTests.swift; sourceTree = ""; }; + 75CF8DAC29C8F2B500CB1524 /* SecureConversationsConfirmationScreenVoiceOverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversationsConfirmationScreenVoiceOverTests.swift; sourceTree = ""; }; 75F58EE027E7D5300065BA2D /* Survey.ViewController.Props.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Survey.ViewController.Props.swift; sourceTree = ""; }; 75FF151327F3A2D600FE7BE2 /* Theme+Survey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Survey.swift"; sourceTree = ""; }; 75FF151627F4E13900FE7BE2 /* Theme.Survey.BooleanQuestion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.Survey.BooleanQuestion.swift; sourceTree = ""; }; @@ -1102,7 +1104,7 @@ 846A5C3D29D1C7B00049B29F /* CallVisualizerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallVisualizerTests.swift; sourceTree = ""; }; 846A5C3F29ED83C50049B29F /* CallVisualizer.Coordinator.DelegateEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallVisualizer.Coordinator.DelegateEvent.swift; sourceTree = ""; }; 846A5C4429F6BEFA0049B29F /* GliaTests+StartEngagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GliaTests+StartEngagement.swift"; sourceTree = ""; }; - 846E822728996A5C008EFBF0 /* AlertViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertViewControllerTests.swift; sourceTree = ""; }; + 846E822728996A5C008EFBF0 /* AlertViewControllerVoiceOverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertViewControllerVoiceOverTests.swift; sourceTree = ""; }; 847A7642285A1914004044D1 /* FileUploadListViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUploadListViewModelTests.swift; sourceTree = ""; }; 8491AEFF2A6FB44200CC3E72 /* GvaGalleryCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaGalleryCardCell.swift; sourceTree = ""; }; 8491AF012A6FBBBA00CC3E72 /* GvaGalleryListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaGalleryListView.swift; sourceTree = ""; }; @@ -1338,12 +1340,14 @@ C06A7585296ECC57006B69A2 /* VisitorCodeStyle.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorCodeStyle.Accessibility.swift; sourceTree = ""; }; C06A7587296ECD75006B69A2 /* Theme+VisitorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+VisitorCode.swift"; sourceTree = ""; }; C07F62452ABC322B003EFC97 /* OrientationManager.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationManager.Mock.swift; sourceTree = ""; }; + C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; + C07F62822AC33BB9003EFC97 /* UIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingView.Mock.swift; sourceTree = ""; }; C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewController.Mock.swift; sourceTree = ""; }; C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionButton.Mock.swift; sourceTree = ""; }; - C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenShareViewControllerTests.swift; sourceTree = ""; }; - C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCallViewControllerTests.swift; sourceTree = ""; }; - C07FA04E29B0E41A00E9FB7F /* VisitorCodeViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisitorCodeViewControllerTests.swift; sourceTree = ""; }; + C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenShareViewControllerVoiceOverTests.swift; sourceTree = ""; }; + C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCallViewControllerVoiceOverTests.swift; sourceTree = ""; }; + C07FA04E29B0E41A00E9FB7F /* VisitorCodeViewControllerVoiceOverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisitorCodeViewControllerVoiceOverTests.swift; sourceTree = ""; }; C0857DE428D470C1008D171D /* Theme+Shadow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Shadow.swift"; sourceTree = ""; }; C0857DE628D470F2008D171D /* Theme+Layer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Layer.swift"; sourceTree = ""; }; C0857DEA28D482D0008D171D /* Theme+Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+Button.swift"; sourceTree = ""; }; @@ -3342,7 +3346,8 @@ 9A1992CE27D61F5400161AAE /* SnapshotTests */ = { isa = PBXGroup; children = ( - 846E822728996A5C008EFBF0 /* AlertViewControllerTests.swift */, + C07F62752AC1BA0E003EFC97 /* extensions */, + 846E822728996A5C008EFBF0 /* AlertViewControllerVoiceOverTests.swift */, AF22C8842A6154780004BF3C /* AlertViewControllerLayoutTests.swift */, AF03A7AE2A6E7DC40081887D /* AlertViewControllerDynamicTypeFontTests.swift */, 9AB3401227F71D5D006E0FE2 /* BubbleViewVoiceOverTests.swift */, @@ -3357,22 +3362,23 @@ 9A1992D627D61F8100161AAE /* ChatViewControllerVoiceOverTests.swift */, AF22C88C2A6188EF0004BF3C /* ChatViewControllerLayoutTests.swift */, AF03A7B62A6EAFBA0081887D /* ChatViewControllerDynamicTypeFontTests.swift */, - C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerTests.swift */, + C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift */, AF22C88E2A618B9D0004BF3C /* ScreenShareViewControllerLayoutTests.swift */, AF03A7B82A6ED1240081887D /* ScreenShareViewControllerDynamicTypeFontTests.swift */, - 75CF8D9029C3A85C00CB1524 /* SecureConversationsWelcomeScreenTests.swift */, + 75CF8D9029C3A85C00CB1524 /* SecureConversationsWelcomeScreenVoiceOverTests.swift */, AF22C8902A6198FF0004BF3C /* SecureConversationsWelcomeScreenLayoutTests.swift */, AF03A7BA2A6ED73E0081887D /* SecureConversationsWelcomeScreenDynamicTypeFontTests.swift */, - 75CF8DAC29C8F2B500CB1524 /* SecureConversationsConfirmationScreenTests.swift */, + 75CF8DAC29C8F2B500CB1524 /* SecureConversationsConfirmationScreenVoiceOverTests.swift */, AF22C8922A619F5C0004BF3C /* SecureConversationsConfirmationScreenLayoutTests.swift */, AF03A7BC2A6EDACF0081887D /* SecureConversationsConfirmationScreenDynamicTypeFontTests.swift */, 9A1992D727D61F8100161AAE /* SnapshotTestCase.swift */, 8458769E2823FD18007AC3DF /* SurveyViewControllerVoiceOverTests.swift */, AF22C8942A61A6B80004BF3C /* SurveyViewControllerLayoutTests.swift */, AF03A7BE2A6EDCBF0081887D /* SurveyViewControllerDynamicTypeFontTests.swift */, - C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerTests.swift */, + C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift */, AF22C8962A61A9BF0004BF3C /* VideoCallViewControllerLayoutTests.swift */, AF03A7C02A6EDE190081887D /* VideoCallViewControllerDynamicTypeFontTests.swift */, + C07FA04E29B0E41A00E9FB7F /* VisitorCodeViewControllerVoiceOverTests.swift */, C07FA04E29B0E41A00E9FB7F /* VisitorCodeViewControllerTests.swift */, AF755FD92A71583900871E36 /* BubbleWindowLayoutTests.swift */, AF22C8982A61AE930004BF3C /* VisitorCodeViewControllerLayoutTests.swift */, @@ -3573,6 +3579,15 @@ path = OrientationManager; sourceTree = ""; }; + C07F62752AC1BA0E003EFC97 /* extensions */ = { + isa = PBXGroup; + children = ( + C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */, + C07F62822AC33BB9003EFC97 /* UIView+Extensions.swift */, + ); + path = extensions; + sourceTree = ""; + }; C096B408297EBCEB00F0C552 /* CallVisualizer */ = { isa = PBXGroup; children = ( @@ -4939,17 +4954,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 846E822828996A5C008EFBF0 /* AlertViewControllerTests.swift in Sources */, + 846E822828996A5C008EFBF0 /* AlertViewControllerVoiceOverTests.swift in Sources */, AF03A7BB2A6ED73E0081887D /* SecureConversationsWelcomeScreenDynamicTypeFontTests.swift in Sources */, - 75CF8D9129C3A85C00CB1524 /* SecureConversationsWelcomeScreenTests.swift in Sources */, + 75CF8D9129C3A85C00CB1524 /* SecureConversationsWelcomeScreenVoiceOverTests.swift in Sources */, AF22C8972A61A9BF0004BF3C /* VideoCallViewControllerLayoutTests.swift in Sources */, + C07F62772AC1BA2B003EFC97 /* UIViewController+Extensions.swift in Sources */, AF03A7BD2A6EDACF0081887D /* SecureConversationsConfirmationScreenDynamicTypeFontTests.swift in Sources */, AF03A7B92A6ED1240081887D /* ScreenShareViewControllerDynamicTypeFontTests.swift in Sources */, + C07F62832AC33BB9003EFC97 /* UIView+Extensions.swift in Sources */, 9AE9E4B527E0EE2E00BFE239 /* CallViewControllerVoiceOverTests.swift in Sources */, AF03A7BF2A6EDCBF0081887D /* SurveyViewControllerDynamicTypeFontTests.swift in Sources */, AF22C8852A6154780004BF3C /* AlertViewControllerLayoutTests.swift in Sources */, AF22C8872A6182AF0004BF3C /* BubbleViewLayoutTests.swift in Sources */, AF03A7C12A6EDE190081887D /* VideoCallViewControllerDynamicTypeFontTests.swift in Sources */, + C07FA05029B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift in Sources */, C07FA05029B0E41A00E9FB7F /* VideoCallViewControllerTests.swift in Sources */, AF755FDA2A71583900871E36 /* BubbleWindowLayoutTests.swift in Sources */, AF22C88D2A6188EF0004BF3C /* ChatViewControllerLayoutTests.swift in Sources */, @@ -4963,10 +4981,10 @@ 9A1992D827D61F8100161AAE /* ChatViewControllerVoiceOverTests.swift in Sources */, AF22C8892A6184C50004BF3C /* CallViewControllerLayoutTests.swift in Sources */, 8458769F2823FD18007AC3DF /* SurveyViewControllerVoiceOverTests.swift in Sources */, - C07FA05129B0E41A00E9FB7F /* VisitorCodeViewControllerTests.swift in Sources */, - 75CF8DAD29C8F2B500CB1524 /* SecureConversationsConfirmationScreenTests.swift in Sources */, + C07FA05129B0E41A00E9FB7F /* VisitorCodeViewControllerVoiceOverTests.swift in Sources */, + 75CF8DAD29C8F2B500CB1524 /* SecureConversationsConfirmationScreenVoiceOverTests.swift in Sources */, 9AB3402928002422006E0FE2 /* ChatCallUpgradeViewVoiceOverTests.swift in Sources */, - C07FA04F29B0E41A00E9FB7F /* ScreenShareViewControllerTests.swift in Sources */, + C07FA04F29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift in Sources */, AF22C8952A61A6B80004BF3C /* SurveyViewControllerLayoutTests.swift in Sources */, 9A1992D927D61F8100161AAE /* SnapshotTestCase.swift in Sources */, AF03A7B52A6EAA950081887D /* ChatCallUpgradeViewDynamicTypeFontTests.swift in Sources */, diff --git a/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift b/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift index eb9ea34a0..bfad7fd7d 100644 --- a/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/AlertViewControllerDynamicTypeFontTests.swift @@ -10,16 +10,8 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { accepted: {}, declined: {} )) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .extra3LargeFont, in: .portrait) + alert.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_mediaUpgradeOffer_extra3Large() { @@ -28,16 +20,8 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { accepted: {}, declined: {} )) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .extra3LargeFont, in: .portrait) + alert.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_messageAlert_extra3Large() { @@ -46,16 +30,8 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { accessibilityIdentifier: nil, dismissed: {} )) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .extra3LargeFont, in: .portrait) + alert.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_singleAction_extra3Large() { @@ -64,16 +40,8 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { accessibilityIdentifier: "mocked-accessibility-identifier", actionTapped: {} )) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .extra3LargeFont, in: .portrait) + alert.assertSnapshot(as: .extra3LargeFont, in: .landscape) } private func alert(ofKind kind: AlertViewController.Kind) -> AlertViewController { @@ -81,7 +49,6 @@ final class AlertViewControllerDynamicTypeFontTests: SnapshotTestCase { kind: kind, viewFactory: .mock() ) - viewController.view.frame = UIScreen.main.bounds return viewController } } diff --git a/SnapshotTests/AlertViewControllerLayoutTests.swift b/SnapshotTests/AlertViewControllerLayoutTests.swift index 390a08cc2..683507736 100644 --- a/SnapshotTests/AlertViewControllerLayoutTests.swift +++ b/SnapshotTests/AlertViewControllerLayoutTests.swift @@ -9,16 +9,8 @@ final class AlertViewControllerLayoutTests: SnapshotTestCase { accepted: {}, declined: {} )) - assertSnapshot( - matching: alert, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .image, in: .portrait) + alert.assertSnapshot(as: .image, in: .landscape) } func test_mediaUpgradeOffer() { @@ -27,16 +19,8 @@ final class AlertViewControllerLayoutTests: SnapshotTestCase { accepted: {}, declined: {} )) - assertSnapshot( - matching: alert, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .image, in: .portrait) + alert.assertSnapshot(as: .image, in: .landscape) } func test_messageAlert() { @@ -45,16 +29,8 @@ final class AlertViewControllerLayoutTests: SnapshotTestCase { accessibilityIdentifier: nil, dismissed: {} )) - assertSnapshot( - matching: alert, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .image, in: .portrait) + alert.assertSnapshot(as: .image, in: .landscape) } func test_singleAction() { @@ -63,16 +39,8 @@ final class AlertViewControllerLayoutTests: SnapshotTestCase { accessibilityIdentifier: "mocked-accessibility-identifier", actionTapped: {} )) - assertSnapshot( - matching: alert, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: alert, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + alert.assertSnapshot(as: .image, in: .portrait) + alert.assertSnapshot(as: .image, in: .landscape) } private func alert(ofKind kind: AlertViewController.Kind) -> AlertViewController { @@ -80,7 +48,6 @@ final class AlertViewControllerLayoutTests: SnapshotTestCase { kind: kind, viewFactory: .mock() ) - viewController.view.frame = UIScreen.main.bounds return viewController } } diff --git a/SnapshotTests/AlertViewControllerTests.swift b/SnapshotTests/AlertViewControllerVoiceOverTests.swift similarity index 58% rename from SnapshotTests/AlertViewControllerTests.swift rename to SnapshotTests/AlertViewControllerVoiceOverTests.swift index 0522cb041..c39ae40fe 100644 --- a/SnapshotTests/AlertViewControllerTests.swift +++ b/SnapshotTests/AlertViewControllerVoiceOverTests.swift @@ -3,18 +3,14 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -final class AlertViewControllerTests: SnapshotTestCase { +final class AlertViewControllerVoiceOverTests: SnapshotTestCase { func test_screenSharingOffer() { let alert = alert(ofKind: .screenShareOffer( .mock(), accepted: {}, declined: {} )) - assertSnapshot( - matching: alert, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + alert.assertSnapshot(as: .accessibilityImage) } func test_mediaUpgradeOffer() { @@ -23,11 +19,7 @@ final class AlertViewControllerTests: SnapshotTestCase { accepted: {}, declined: {} )) - assertSnapshot( - matching: alert, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + alert.assertSnapshot(as: .accessibilityImage) } func test_messageAlert() { @@ -36,11 +28,7 @@ final class AlertViewControllerTests: SnapshotTestCase { accessibilityIdentifier: nil, dismissed: {} )) - assertSnapshot( - matching: alert, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + alert.assertSnapshot(as: .accessibilityImage) } func test_singleAction() { @@ -49,11 +37,7 @@ final class AlertViewControllerTests: SnapshotTestCase { accessibilityIdentifier: "mocked-accessibility-identifier", actionTapped: {} )) - assertSnapshot( - matching: alert, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + alert.assertSnapshot(as: .accessibilityImage) } private func alert(ofKind kind: AlertViewController.Kind) -> AlertViewController { @@ -61,7 +45,6 @@ final class AlertViewControllerTests: SnapshotTestCase { kind: kind, viewFactory: .mock() ) - viewController.view.frame = UIScreen.main.bounds return viewController } } diff --git a/SnapshotTests/BubbleViewDynamicTypeFontTests.swift b/SnapshotTests/BubbleViewDynamicTypeFontTests.swift index e3f65d375..89bfab933 100644 --- a/SnapshotTests/BubbleViewDynamicTypeFontTests.swift +++ b/SnapshotTests/BubbleViewDynamicTypeFontTests.swift @@ -7,14 +7,7 @@ final class BubbleViewDynamicTypeFontTests: SnapshotTestCase { func test_bubble_extra3Large() { let bubble = ViewFactory.mock().makeBubbleView() bubble.frame = .init(origin: .zero, size: .init(width: 50, height: 50)) - assertSnapshot( - matching: bubble, - as: .extra3LargeFontStrategy - ) - assertSnapshot( - matching: bubble, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + bubble.assertSnapshot(as: .extra3LargeFont, in: .portrait) + bubble.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } diff --git a/SnapshotTests/BubbleViewLayoutTests.swift b/SnapshotTests/BubbleViewLayoutTests.swift index d3237b534..d18734882 100644 --- a/SnapshotTests/BubbleViewLayoutTests.swift +++ b/SnapshotTests/BubbleViewLayoutTests.swift @@ -6,14 +6,7 @@ final class BubbleViewLayoutTests: SnapshotTestCase { func test_bubble() { let bubble = ViewFactory.mock().makeBubbleView() bubble.frame = .init(origin: .zero, size: .init(width: 50, height: 50)) - assertSnapshot( - matching: bubble, - as: .image - ) - assertSnapshot( - matching: bubble, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + bubble.assertSnapshot(as: .image, in: .portrait) + bubble.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/BubbleViewVoiceOverTests.swift b/SnapshotTests/BubbleViewVoiceOverTests.swift index 6214c5e43..9bda941f6 100644 --- a/SnapshotTests/BubbleViewVoiceOverTests.swift +++ b/SnapshotTests/BubbleViewVoiceOverTests.swift @@ -7,6 +7,6 @@ final class BubbleViewVoiceOverTests: SnapshotTestCase { func test_bubble() { let bubble = ViewFactory.mock().makeBubbleView() bubble.frame = .init(origin: .zero, size: .init(width: 50, height: 50)) - assertSnapshot(matching: bubble, as: .accessibilityImage(precision: SnapshotTestCase.possiblePrecision)) + bubble.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/BubbleWindowLayoutTests.swift b/SnapshotTests/BubbleWindowLayoutTests.swift index fc827cc23..5640e3413 100644 --- a/SnapshotTests/BubbleWindowLayoutTests.swift +++ b/SnapshotTests/BubbleWindowLayoutTests.swift @@ -14,6 +14,7 @@ final class BubbleWindowLayoutTests: XCTestCase { ) ) bubbleWindow.makeKeyAndVisible() - assertSnapshot(matching: bubbleWindow, as: .image) + bubbleWindow.assertSnapshot(as: .image, in: .portrait) + bubbleWindow.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift b/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift index 6498c88ea..7d3dbcd41 100644 --- a/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/CallViewControllerDynamicTypeFontTests.swift @@ -5,91 +5,37 @@ import XCTest final class CallViewControllerDynamicTypeFontTests: SnapshotTestCase { func test_audioCallQueueState_extra3Large() throws { let viewController = try CallViewController.mockAudioCallQueueState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_audioCallConnectingState_extra3Large() throws { let viewController = try CallViewController.mockAudioCallConnectingState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_audioCallConnectedState_extra3Large() throws { let viewController = try CallViewController.mockAudioCallConnectedState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_mockVideoCallConnectingState_extra3Large() throws { let viewController = try CallViewController.mockVideoCallConnectingState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_mockVideoCallQueueState_extra3Large() throws { let viewController = try CallViewController.mockVideoCallQueueState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_mockVideoCallConnectedState_extra3Large() throws { let viewController = try CallViewController.mockVideoCallConnectedState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } diff --git a/SnapshotTests/CallViewControllerLayoutTests.swift b/SnapshotTests/CallViewControllerLayoutTests.swift index 7ad4f789a..922f102d0 100644 --- a/SnapshotTests/CallViewControllerLayoutTests.swift +++ b/SnapshotTests/CallViewControllerLayoutTests.swift @@ -5,91 +5,37 @@ import XCTest final class CallViewControllerLayoutTests: SnapshotTestCase { func test_audioCallQueueState() throws { let viewController = try CallViewController.mockAudioCallQueueState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_audioCallConnectingState() throws { let viewController = try CallViewController.mockAudioCallConnectingState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_audioCallConnectedState() throws { let viewController = try CallViewController.mockAudioCallConnectedState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_mockVideoCallConnectingState() throws { let viewController = try CallViewController.mockVideoCallConnectingState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_mockVideoCallQueueState() throws { let viewController = try CallViewController.mockVideoCallQueueState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_mockVideoCallConnectedState() throws { let viewController = try CallViewController.mockVideoCallConnectedState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/CallViewControllerVoiceOverTests.swift b/SnapshotTests/CallViewControllerVoiceOverTests.swift index e6a365781..2fab3b6ad 100644 --- a/SnapshotTests/CallViewControllerVoiceOverTests.swift +++ b/SnapshotTests/CallViewControllerVoiceOverTests.swift @@ -6,61 +6,31 @@ import XCTest final class CallViewControllerVoiceOverTests: SnapshotTestCase { func test_audioCallQueueState() throws { let viewController = try CallViewController.mockAudioCallQueueState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_audioCallConnectingState() throws { let viewController = try CallViewController.mockAudioCallConnectingState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_audioCallConnectedState() throws { let viewController = try CallViewController.mockAudioCallConnectedState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_mockVideoCallConnectingState() throws { let viewController = try CallViewController.mockVideoCallConnectingState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_mockVideoCallQueueState() throws { let viewController = try CallViewController.mockVideoCallQueueState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_mockVideoCallConnectedState() throws { let viewController = try CallViewController.mockVideoCallConnectedState() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift b/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift index 295477e13..e968e7125 100644 --- a/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift +++ b/SnapshotTests/ChatCallUpgradeViewDynamicTypeFontTests.swift @@ -6,28 +6,14 @@ final class ChatCallUpgradeViewDynamicTypeFontTests: SnapshotTestCase { func test_chatCallUpgradeViewToAudio_extra3Large() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.audioUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 160)) - assertSnapshot( - matching: upgradeView, - as: .extra3LargeFontStrategy - ) - assertSnapshot( - matching: upgradeView, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + upgradeView.assertSnapshot(as: .extra3LargeFont, in: .portrait) + upgradeView.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_chatCallUpgradeViewToVideo_extra3Large() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.videoUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 160)) - assertSnapshot( - matching: upgradeView, - as: .extra3LargeFontStrategy - ) - assertSnapshot( - matching: upgradeView, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + upgradeView.assertSnapshot(as: .extra3LargeFont, in: .portrait) + upgradeView.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } diff --git a/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift b/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift index da552c62b..161d4a1ff 100644 --- a/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift +++ b/SnapshotTests/ChatCallUpgradeViewLayoutTests.swift @@ -6,28 +6,14 @@ final class ChatCallUpgradeViewLayoutTests: SnapshotTestCase { func test_chatCallUpgradeViewToAudio() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.audioUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 120)) - assertSnapshot( - matching: upgradeView, - as: .image - ) - assertSnapshot( - matching: upgradeView, - as: .image, - named: nameForDevice(.landscape) - ) + upgradeView.assertSnapshot(as: .image, in: .portrait) + upgradeView.assertSnapshot(as: .image, in: .landscape) } func test_chatCallUpgradeViewToVideo() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.videoUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 120)) - assertSnapshot( - matching: upgradeView, - as: .image - ) - assertSnapshot( - matching: upgradeView, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + upgradeView.assertSnapshot(as: .image, in: .portrait) + upgradeView.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift b/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift index 5dd76d736..e7a74981d 100644 --- a/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift +++ b/SnapshotTests/ChatCallUpgradeViewVoiceOverTests.swift @@ -7,18 +7,12 @@ final class ChatCallUpgradeViewVoiceOverTests: SnapshotTestCase { func test_chatCallUpgradeViewToAudio() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.audioUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 120)) - assertSnapshot( - matching: upgradeView, - as: .accessibilityImage(precision: SnapshotTestCase.possiblePrecision) - ) + upgradeView.assertSnapshot(as: .accessibilityImage) } func test_chatCallUpgradeViewToVideo() { let upgradeView = ChatCallUpgradeView(with: Theme.mock().chat.videoUpgrade, duration: .init(with: .zero)) upgradeView.frame = .init(origin: .zero, size: .init(width: 300, height: 120)) - assertSnapshot( - matching: upgradeView, - as: .accessibilityImage(precision: SnapshotTestCase.possiblePrecision) - ) + upgradeView.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift b/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift index c694b1d81..62b3b34b4 100644 --- a/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/ChatViewControllerDynamicTypeFontTests.swift @@ -5,47 +5,20 @@ import XCTest final class ChatViewControllerDynamicTypeFontTests: SnapshotTestCase { func test_messagesFromHistory_extra3Large() { let viewController = ChatViewController.mockHistoryMessagesScreen() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_visitorUploadedFileStates_extra3Large() throws { let viewController = try ChatViewController.mockVisitorFileUploadStates() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_choiceCard_extra3Large() throws { let viewController = try ChatViewController.mockChoiceCard() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_visitorFileDownloadStates_extra3Large() throws { @@ -61,15 +34,7 @@ final class ChatViewControllerDynamicTypeFontTests: SnapshotTestCase { chatMessages[1].downloads[0].state.value = .downloading(progress: .init(with: 0.5)) chatMessages[2].downloads[0].state.value = .downloaded(.mock()) chatMessages[3].downloads[0].state.value = .error(.deleted) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } diff --git a/SnapshotTests/ChatViewControllerLayoutTests.swift b/SnapshotTests/ChatViewControllerLayoutTests.swift index cfb016713..10480549a 100644 --- a/SnapshotTests/ChatViewControllerLayoutTests.swift +++ b/SnapshotTests/ChatViewControllerLayoutTests.swift @@ -5,92 +5,38 @@ import XCTest final class ChatViewControllerLayoutTests: SnapshotTestCase { func test_messagesFromHistory() { let viewController = ChatViewController.mockHistoryMessagesScreen() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_visitorUploadedFileStates() throws { let viewController = try ChatViewController.mockVisitorFileUploadStates() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_choiceCard() throws { let viewController = try ChatViewController.mockChoiceCard() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_gvaPersistentButton() throws { let viewController = try ChatViewController.mockGvaPersistentButton() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_gvaResponseText() throws { let viewController = try ChatViewController.mockGvaResponseText() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_gvaGalleryCard() throws { let viewController = try ChatViewController.mockGvaGalleryCards() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_gvaQuickReply() throws { @@ -106,16 +52,8 @@ final class ChatViewControllerLayoutTests: SnapshotTestCase { ) view.frame = .init(origin: .zero, size: .init(width: 350, height: 200)) view.collectionView.heightAnchor.constraint(equalToConstant: 200).isActive = true - assertSnapshot( - matching: view, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: view, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + view.assertSnapshot(as: .image, in: .portrait) + view.assertSnapshot(as: .image, in: .landscape) } func test_visitorFileDownloadStates() throws { @@ -131,15 +69,7 @@ final class ChatViewControllerLayoutTests: SnapshotTestCase { chatMessages[1].downloads[0].state.value = .downloading(progress: .init(with: 0.5)) chatMessages[2].downloads[0].state.value = .downloaded(.mock()) chatMessages[3].downloads[0].state.value = .error(.deleted) - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/ChatViewControllerVoiceOverTests.swift b/SnapshotTests/ChatViewControllerVoiceOverTests.swift index 40fa87f20..c08c7a92a 100644 --- a/SnapshotTests/ChatViewControllerVoiceOverTests.swift +++ b/SnapshotTests/ChatViewControllerVoiceOverTests.swift @@ -6,32 +6,17 @@ import XCTest final class ChatViewControllerVoiceOverTests: SnapshotTestCase { func test_messagesFromHistory() { let viewController = ChatViewController.mockHistoryMessagesScreen() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_visitorUploadedFileStates() throws { let viewController = try ChatViewController.mockVisitorFileUploadStates() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_choiceCard() throws { let viewController = try ChatViewController.mockChoiceCard() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_visitorFileDownloadStates() throws { @@ -47,41 +32,22 @@ final class ChatViewControllerVoiceOverTests: SnapshotTestCase { chatMessages[1].downloads[0].state.value = .downloading(progress: .init(with: 0.5)) chatMessages[2].downloads[0].state.value = .downloaded(.mock()) chatMessages[3].downloads[0].state.value = .error(.deleted) - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: self.nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_gvaPersistentButton() throws { let viewController = try ChatViewController.mockGvaPersistentButton() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_gvaResponseText() throws { let viewController = try ChatViewController.mockGvaResponseText() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_gvaGalleryCard() throws { let viewController = try ChatViewController.mockGvaGalleryCards() - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_gvaQuickReply() throws { @@ -97,10 +63,6 @@ final class ChatViewControllerVoiceOverTests: SnapshotTestCase { ) view.frame = .init(origin: .zero, size: .init(width: 350, height: 200)) view.collectionView.heightAnchor.constraint(equalToConstant: 200).isActive = true - assertSnapshot( - matching: view, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: self.nameForDevice() - ) + view.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift b/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift index 88ebc2db7..4ffcbab25 100644 --- a/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift @@ -21,18 +21,8 @@ final class ScreenShareViewControllerDynamicTypeFontTests: SnapshotTestCase { ) ) let screenShareViewController = CallVisualizer.ScreenSharingViewController(props: props) - screenShareViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: screenShareViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: screenShareViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + screenShareViewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + screenShareViewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } // swiftlint:enable type_name diff --git a/SnapshotTests/ScreenShareViewControllerLayoutTests.swift b/SnapshotTests/ScreenShareViewControllerLayoutTests.swift index 857fe9128..dd64fab18 100644 --- a/SnapshotTests/ScreenShareViewControllerLayoutTests.swift +++ b/SnapshotTests/ScreenShareViewControllerLayoutTests.swift @@ -20,17 +20,7 @@ final class ScreenShareViewControllerLayoutTests: SnapshotTestCase { ) ) let screenShareViewController = CallVisualizer.ScreenSharingViewController(props: props) - screenShareViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: screenShareViewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: screenShareViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + screenShareViewController.assertSnapshot(as: .image, in: .portrait) + screenShareViewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/ScreenShareViewControllerTests.swift b/SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift similarity index 73% rename from SnapshotTests/ScreenShareViewControllerTests.swift rename to SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift index 319343539..5ca81ba33 100644 --- a/SnapshotTests/ScreenShareViewControllerTests.swift +++ b/SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -final class ScreenShareViewControllerTests: SnapshotTestCase { +final class ScreenShareViewControllerVoiceOverTests: SnapshotTestCase { func testScreenShareViewController() { let theme = Theme() let font = theme.font @@ -21,12 +21,6 @@ final class ScreenShareViewControllerTests: SnapshotTestCase { ) ) let screenShareViewController = CallVisualizer.ScreenSharingViewController(props: props) - screenShareViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: screenShareViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + screenShareViewController.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift index a81d37442..9f11b5123 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenDynamicTypeFontTests.swift @@ -15,18 +15,8 @@ final class SecureConversationsConfirmationScreenDynamicTypeFontTests: SnapshotT delegate: nil ) let viewController = SecureConversations.ConfirmationViewController(model: model) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } // swiftlint:enable type_name diff --git a/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift index 87c7ac6db..2fef40481 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenLayoutTests.swift @@ -14,17 +14,7 @@ final class SecureConversationsConfirmationScreenLayoutTests: SnapshotTestCase { delegate: nil ) let viewController = SecureConversations.ConfirmationViewController(model: model) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/SecureConversationsConfirmationScreenTests.swift b/SnapshotTests/SecureConversationsConfirmationScreenVoiceOverTests.swift similarity index 63% rename from SnapshotTests/SecureConversationsConfirmationScreenTests.swift rename to SnapshotTests/SecureConversationsConfirmationScreenVoiceOverTests.swift index 2a144d8b3..577760d73 100644 --- a/SnapshotTests/SecureConversationsConfirmationScreenTests.swift +++ b/SnapshotTests/SecureConversationsConfirmationScreenVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -final class SecureConversationsConfirmationScreenTests: SnapshotTestCase { +final class SecureConversationsConfirmationScreenVoiceOverTests: SnapshotTestCase { let theme = Theme.mock() func test_confirmationView() { @@ -15,12 +15,6 @@ final class SecureConversationsConfirmationScreenTests: SnapshotTestCase { delegate: nil ) let viewController = SecureConversations.ConfirmationViewController(model: model) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: self.nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift b/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift index 59f707f78..2c693f8db 100644 --- a/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift +++ b/SnapshotTests/SecureConversationsWelcomeScreenDynamicTypeFontTests.swift @@ -16,18 +16,8 @@ final class SecureConversationsWelcomeScreenDynamicTypeFontTests: SnapshotTestCa props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_welcomeWithAttachments_extra3Large() { @@ -43,18 +33,8 @@ final class SecureConversationsWelcomeScreenDynamicTypeFontTests: SnapshotTestCa props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_welcomeViewController_withValidationError_extra3Large() { @@ -64,18 +44,8 @@ final class SecureConversationsWelcomeScreenDynamicTypeFontTests: SnapshotTestCa props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } // MARK: - Helpers diff --git a/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift b/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift index 6c3d40a32..3ad2d23c5 100644 --- a/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift +++ b/SnapshotTests/SecureConversationsWelcomeScreenLayoutTests.swift @@ -15,18 +15,8 @@ final class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_welcomeWithAttachments() { @@ -42,18 +32,8 @@ final class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_welcomeViewController_withValidationError() { @@ -63,18 +43,8 @@ final class SecureConversationsWelcomeScreenLayoutTests: SnapshotTestCase { props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController.view, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } // MARK: - Helpers diff --git a/SnapshotTests/SecureConversationsWelcomeScreenTests.swift b/SnapshotTests/SecureConversationsWelcomeScreenVoiceOverTests.swift similarity index 82% rename from SnapshotTests/SecureConversationsWelcomeScreenTests.swift rename to SnapshotTests/SecureConversationsWelcomeScreenVoiceOverTests.swift index 4d97ae2c6..0461fe44b 100644 --- a/SnapshotTests/SecureConversationsWelcomeScreenTests.swift +++ b/SnapshotTests/SecureConversationsWelcomeScreenVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -final class SecureConversationsWelcomeScreenTests: SnapshotTestCase { +final class SecureConversationsWelcomeScreenVoiceOverTests: SnapshotTestCase { let theme = Theme.mock() func test_welcomeView() { @@ -16,13 +16,7 @@ final class SecureConversationsWelcomeScreenTests: SnapshotTestCase { props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: self.nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_welcomeWithAttachments() { @@ -38,13 +32,7 @@ final class SecureConversationsWelcomeScreenTests: SnapshotTestCase { props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: self.nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_welcomeViewController_withValidationError() { @@ -54,13 +42,7 @@ final class SecureConversationsWelcomeScreenTests: SnapshotTestCase { props: .welcome(props), environment: .init(gcd: .live, uiScreen: .mock, notificationCenter: .mock) ) - viewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: viewController.view, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: self.nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } // MARK: - Helpers diff --git a/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift b/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift index 37f98c751..0ff909f11 100644 --- a/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/SurveyViewControllerDynamicTypeFontTests.swift @@ -9,17 +9,8 @@ final class SurveyViewControllerDynamicTypeFontTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .emptyPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_filledSurvey_extra3Large() { @@ -28,17 +19,8 @@ final class SurveyViewControllerDynamicTypeFontTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .filledPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func test_emptySurveyErrorState_extra3Large() { @@ -47,16 +29,7 @@ final class SurveyViewControllerDynamicTypeFontTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .errorPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } diff --git a/SnapshotTests/SurveyViewControllerLayoutTests.swift b/SnapshotTests/SurveyViewControllerLayoutTests.swift index 23961a2c2..58f85c817 100644 --- a/SnapshotTests/SurveyViewControllerLayoutTests.swift +++ b/SnapshotTests/SurveyViewControllerLayoutTests.swift @@ -9,17 +9,8 @@ final class SurveyViewControllerLayoutTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .emptyPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_filledSurvey() { @@ -28,17 +19,8 @@ final class SurveyViewControllerLayoutTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .filledPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func test_emptySurveyErrorState() { @@ -47,16 +29,7 @@ final class SurveyViewControllerLayoutTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .errorPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: viewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/SurveyViewControllerVoiceOverTests.swift b/SnapshotTests/SurveyViewControllerVoiceOverTests.swift index 4d06d1def..1a41f6403 100644 --- a/SnapshotTests/SurveyViewControllerVoiceOverTests.swift +++ b/SnapshotTests/SurveyViewControllerVoiceOverTests.swift @@ -10,12 +10,7 @@ final class SurveyViewControllerVoiceOverTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .emptyPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_filledSurvey() { @@ -24,12 +19,7 @@ final class SurveyViewControllerVoiceOverTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .filledPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } func test_emptySurveyErrorState() { @@ -38,11 +28,6 @@ final class SurveyViewControllerVoiceOverTests: SnapshotTestCase { environment: .init(notificationCenter: .mock), props: .errorPropsMock() ) - viewController.view.frame = UIScreen.main.bounds - assertSnapshot( - matching: viewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + viewController.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift b/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift index aa0b8b9bc..cf0b80b3e 100644 --- a/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/VideoCallViewControllerDynamicTypeFontTests.swift @@ -48,19 +48,9 @@ final class VideoCallViewControllerDynamicTypeFontTests: SnapshotTestCase { ) let props: CallVisualizer.VideoCallViewController.Props = .init(videoCallViewProps: videoCallViewProps) - let videoCallViewController: CallVisualizer.VideoCallViewController = .mock(props: props) - videoCallViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: videoCallViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: videoCallViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController: CallVisualizer.VideoCallViewController = .mock(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } // swiftlint:enable type_name diff --git a/SnapshotTests/VideoCallViewControllerLayoutTests.swift b/SnapshotTests/VideoCallViewControllerLayoutTests.swift index f49b05fda..387ed0249 100644 --- a/SnapshotTests/VideoCallViewControllerLayoutTests.swift +++ b/SnapshotTests/VideoCallViewControllerLayoutTests.swift @@ -47,18 +47,8 @@ final class VideoCallViewControllerLayoutTests: SnapshotTestCase { ) let props: CallVisualizer.VideoCallViewController.Props = .init(videoCallViewProps: videoCallViewProps) - let videoCallViewController: CallVisualizer.VideoCallViewController = .mock(props: props) - videoCallViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: videoCallViewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: videoCallViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController: CallVisualizer.VideoCallViewController = .mock(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/VideoCallViewControllerTests.swift b/SnapshotTests/VideoCallViewControllerVoiceOverTests.swift similarity index 84% rename from SnapshotTests/VideoCallViewControllerTests.swift rename to SnapshotTests/VideoCallViewControllerVoiceOverTests.swift index a0c19b532..a407f8d4b 100644 --- a/SnapshotTests/VideoCallViewControllerTests.swift +++ b/SnapshotTests/VideoCallViewControllerVoiceOverTests.swift @@ -3,7 +3,7 @@ import AccessibilitySnapshot import SnapshotTesting import XCTest -final class VideoCallViewControllerTests: SnapshotTestCase { +final class VideoCallViewControllerVoiceOverTests: SnapshotTestCase { func testVideoCallViewController() { let videoCallViewProps: CallVisualizer.VideoCallView.Props = .mock( buttonBarProps: .mock( @@ -48,13 +48,7 @@ final class VideoCallViewControllerTests: SnapshotTestCase { ) let props: CallVisualizer.VideoCallViewController.Props = .init(videoCallViewProps: videoCallViewProps) - let videoCallViewController: CallVisualizer.VideoCallViewController = .mock(props: props) - videoCallViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: videoCallViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) + let viewController: CallVisualizer.VideoCallViewController = .mock(props: props) + viewController.assertSnapshot(as: .accessibilityImage) } } diff --git a/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift b/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift index 14a1bcbe1..313fa03fa 100644 --- a/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/VisitorCodeViewControllerDynamicTypeFontTests.swift @@ -11,19 +11,9 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { viewState: .loading ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func testVisitorCodeAlertWhenError() { @@ -33,19 +23,9 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { viewState: .error(refreshTap: .nop) ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func testVisitorCodeAlertWhenSuccess() { @@ -55,19 +35,9 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { viewState: .success(visitorCode: "12345") ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func testVisitorCodeEmbeddedWhenLoading() { @@ -77,19 +47,9 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { viewState: .loading ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func testVisitorCodeEmbeddedWhenError() { @@ -99,19 +59,9 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { viewState: .error(refreshTap: .nop) ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } func testVisitorCodeEmbeddedWhenSuccess() { let props: CallVisualizer.VisitorCodeViewController.Props = .init( @@ -120,19 +70,9 @@ final class VisitorCodeViewControllerDynamicTypeFontTests: SnapshotTestCase { viewState: .success(visitorCode: "12345") ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategy, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .extra3LargeFontStrategyLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } // swiftlint:enable type_name diff --git a/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift b/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift index 0ce24ebfa..08189628d 100644 --- a/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift +++ b/SnapshotTests/VisitorCodeViewControllerLayoutTests.swift @@ -10,19 +10,9 @@ final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { viewState: .loading ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .image, - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func testVisitorCodeAlertWhenError() { @@ -32,19 +22,9 @@ final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { viewState: .error(refreshTap: .nop) ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func testVisitorCodeAlertWhenSuccess() { @@ -54,19 +34,9 @@ final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { viewState: .success(visitorCode: "12345") ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func testVisitorCodeEmbeddedWhenLoading() { @@ -76,19 +46,9 @@ final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { viewState: .loading ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func testVisitorCodeEmbeddedWhenError() { @@ -98,19 +58,9 @@ final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { viewState: .error(refreshTap: .nop) ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } func testVisitorCodeEmbeddedWhenSuccess() { let props: CallVisualizer.VisitorCodeViewController.Props = .init( @@ -119,18 +69,8 @@ final class VisitorCodeViewControllerLayoutTests: SnapshotTestCase { viewState: .success(visitorCode: "12345") ) ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - assertSnapshot( - matching: visitorCodeViewController, - as: .imageLandscape, - named: nameForDevice(.landscape) - ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/VisitorCodeViewControllerTests.swift b/SnapshotTests/VisitorCodeViewControllerTests.swift deleted file mode 100644 index da52ad845..000000000 --- a/SnapshotTests/VisitorCodeViewControllerTests.swift +++ /dev/null @@ -1,107 +0,0 @@ -import AccessibilitySnapshot -@testable import GliaWidgets -import SnapshotTesting -import XCTest - -final class VisitorCodeViewControllerTests: SnapshotTestCase { - func testVisitorCodeAlertWhenLoading() { - let props: CallVisualizer.VisitorCodeViewController.Props = .init( - visitorCodeViewProps: .init( - viewType: .alert(closeButtonTap: .nop), - viewState: .loading - ) - ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - } - - func testVisitorCodeAlertWhenError() { - let props: CallVisualizer.VisitorCodeViewController.Props = .init( - visitorCodeViewProps: .init( - viewType: .alert(closeButtonTap: .nop), - viewState: .error(refreshTap: .nop) - ) - ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - } - - func testVisitorCodeAlertWhenSuccess() { - let props: CallVisualizer.VisitorCodeViewController.Props = .init( - visitorCodeViewProps: .init( - viewType: .alert(closeButtonTap: .nop), - viewState: .success(visitorCode: "12345") - ) - ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - } - - func testVisitorCodeEmbeddedWhenLoading() { - let props: CallVisualizer.VisitorCodeViewController.Props = .init( - visitorCodeViewProps: .init( - viewType: .embedded, - viewState: .loading - ) - ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - } - - func testVisitorCodeEmbeddedWhenError() { - let props: CallVisualizer.VisitorCodeViewController.Props = .init( - visitorCodeViewProps: .init( - viewType: .embedded, - viewState: .error(refreshTap: .nop) - ) - ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - } - func testVisitorCodeEmbeddedWhenSuccess() { - let props: CallVisualizer.VisitorCodeViewController.Props = .init( - visitorCodeViewProps: .init( - viewType: .embedded, - viewState: .success(visitorCode: "12345") - ) - ) - let visitorCodeViewController = CallVisualizer.VisitorCodeViewController(props: props) - visitorCodeViewController.view.frame = UIScreen.main.bounds - - assertSnapshot( - matching: visitorCodeViewController, - as: .accessibilityImage(precision: Self.possiblePrecision), - named: nameForDevice() - ) - } -} diff --git a/SnapshotTests/VisitorCodeViewControllerVoiceOverTests.swift b/SnapshotTests/VisitorCodeViewControllerVoiceOverTests.swift new file mode 100644 index 000000000..8f8cbe0d1 --- /dev/null +++ b/SnapshotTests/VisitorCodeViewControllerVoiceOverTests.swift @@ -0,0 +1,71 @@ +import AccessibilitySnapshot +@testable import GliaWidgets +import SnapshotTesting +import XCTest + +final class VisitorCodeViewControllerVoiceOverTests: SnapshotTestCase { + func testVisitorCodeAlertWhenLoading() { + let props: CallVisualizer.VisitorCodeViewController.Props = .init( + visitorCodeViewProps: .init( + viewType: .alert(closeButtonTap: .nop), + viewState: .loading + ) + ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .accessibilityImage) + } + + func testVisitorCodeAlertWhenError() { + let props: CallVisualizer.VisitorCodeViewController.Props = .init( + visitorCodeViewProps: .init( + viewType: .alert(closeButtonTap: .nop), + viewState: .error(refreshTap: .nop) + ) + ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .accessibilityImage) + } + + func testVisitorCodeAlertWhenSuccess() { + let props: CallVisualizer.VisitorCodeViewController.Props = .init( + visitorCodeViewProps: .init( + viewType: .alert(closeButtonTap: .nop), + viewState: .success(visitorCode: "12345") + ) + ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .accessibilityImage) + } + + func testVisitorCodeEmbeddedWhenLoading() { + let props: CallVisualizer.VisitorCodeViewController.Props = .init( + visitorCodeViewProps: .init( + viewType: .embedded, + viewState: .loading + ) + ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .accessibilityImage) + } + + func testVisitorCodeEmbeddedWhenError() { + let props: CallVisualizer.VisitorCodeViewController.Props = .init( + visitorCodeViewProps: .init( + viewType: .embedded, + viewState: .error(refreshTap: .nop) + ) + ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .accessibilityImage) + } + func testVisitorCodeEmbeddedWhenSuccess() { + let props: CallVisualizer.VisitorCodeViewController.Props = .init( + visitorCodeViewProps: .init( + viewType: .embedded, + viewState: .success(visitorCode: "12345") + ) + ) + let viewController = CallVisualizer.VisitorCodeViewController(props: props) + viewController.assertSnapshot(as: .accessibilityImage) + } +} diff --git a/SnapshotTests/extensions/UIView+Extensions.swift b/SnapshotTests/extensions/UIView+Extensions.swift new file mode 100644 index 000000000..efc142e2b --- /dev/null +++ b/SnapshotTests/extensions/UIView+Extensions.swift @@ -0,0 +1,66 @@ +import UIKit +import SnapshotTesting + +extension UIView { + func assertSnapshot( + as mode: SnapshotMode, + in orientation: SnapshotOrientation = .portrait, + named name: String? = nil, + record recording: Bool = false, + file: StaticString = #file, + functionName: String = #function, + line: UInt = #line + ) { + let snapshotting: Snapshotting + switch mode { + case .accessibilityImage: + snapshotting = .accessibilityImage(precision: SnapshotTestCase.possiblePrecision) + case .image: + snapshotting = orientation == .portrait ? .image : .imageLandscape + case .extra3LargeFont: + snapshotting = orientation == .portrait ? .extra3LargeFontStrategy : .extra3LargeFontStrategyLandscape + } + let snapshotName = snapshotName(name, orientation: orientation) + SnapshotTesting.assertSnapshot( + matching: self, + as: snapshotting, + named: snapshotName, + record: recording, + file: file, + testName: functionName, + line: line + ) + } + + func snapshotName( + _ baseName: String? = nil, + orientation: SnapshotOrientation + ) -> String { + let size = UIScreen.main.bounds.size + let scale = UIScreen.main.scale + let version = UIDevice.current.systemVersion + let deviceName = "\(Int(size.width))x\(Int(size.height))-\(version)-\(Int(scale))x" + + switch orientation { + case .portrait: + return [baseName, deviceName] + .compactMap { $0 } + .joined(separator: "-") + case .landscape: + return [baseName, deviceName, "landscape"] + .compactMap { $0 } + .joined(separator: "-") + } + } + + enum SnapshotOrientation { + case portrait + case landscape + } + + enum SnapshotMode { + case accessibilityImage + case image + case extra3LargeFont + } +} diff --git a/SnapshotTests/extensions/UIViewController+Extensions.swift b/SnapshotTests/extensions/UIViewController+Extensions.swift new file mode 100644 index 000000000..c5c81f345 --- /dev/null +++ b/SnapshotTests/extensions/UIViewController+Extensions.swift @@ -0,0 +1,68 @@ +import UIKit +import SnapshotTesting + +extension UIViewController { + func assertSnapshot( + as mode: SnapshotMode, + in orientation: SnapshotOrientation = .portrait, + bounds: CGRect = UIScreen.main.bounds, + named name: String? = nil, + record recording: Bool = false, + file: StaticString = #file, + functionName: String = #function, + line: UInt = #line + ) { + self.view.bounds = bounds + let snapshotting: Snapshotting + switch mode { + case .accessibilityImage: + snapshotting = .accessibilityImage(precision: SnapshotTestCase.possiblePrecision) + case .image: + snapshotting = orientation == .portrait ? .image : .imageLandscape + case .extra3LargeFont: + snapshotting = orientation == .portrait ? .extra3LargeFontStrategy : .extra3LargeFontStrategyLandscape + } + let snapshotName = snapshotName(name, orientation: orientation) + SnapshotTesting.assertSnapshot( + matching: self, + as: snapshotting, + named: snapshotName, + record: recording, + file: file, + testName: functionName, + line: line + ) + } + + func snapshotName( + _ baseName: String? = nil, + orientation: SnapshotOrientation + ) -> String { + let size = UIScreen.main.bounds.size + let scale = UIScreen.main.scale + let version = UIDevice.current.systemVersion + let deviceName = "\(Int(size.width))x\(Int(size.height))-\(version)-\(Int(scale))x" + + switch orientation { + case .portrait: + return [baseName, deviceName] + .compactMap { $0 } + .joined(separator: "-") + case .landscape: + return [baseName, deviceName, "landscape"] + .compactMap { $0 } + .joined(separator: "-") + } + } + + enum SnapshotOrientation { + case portrait + case landscape + } + + enum SnapshotMode { + case accessibilityImage + case image + case extra3LargeFont + } +} From 9fa59cc05ea934971180338f74db0efb20aa1461 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Wed, 16 Aug 2023 13:27:04 +0300 Subject: [PATCH 10/40] Update strings in Localizable.string There were a couple of errors in naming and in the strings, so I updated them. MOB-2507 --- GliaWidgets/Localization.swift | 13 +++---------- GliaWidgets/Resources/en.lproj/Localizable.strings | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index 886467e80..a28bc522e 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -371,11 +371,6 @@ internal enum Localization { /// Audio internal static let name = Localization.tr("Localizable", "media.audio.name", fallback: "Audio") } - internal enum Messaging { - /// Send a message and we’ll get back to you - /// within 48 hours - internal static let description = Localization.tr("Localizable", "media.messaging.description", fallback: "Send a message and we’ll get back to you \nwithin 48 hours") - } internal enum Phone { /// Phone internal static let name = Localization.tr("Localizable", "media.phone.name", fallback: "Phone") @@ -421,6 +416,8 @@ internal enum Localization { internal static let messageLengthWarning = Localization.tr("Localizable", "message_center.welcome.message_length_warning", fallback: "The message cannot exceed 10000 characters.") /// Your message internal static let messageTitle = Localization.tr("Localizable", "message_center.welcome.message_title", fallback: "Your message") + /// Send a message and we’ll get back to you within 48 hours + internal static let subtitle = Localization.tr("Localizable", "message_center.welcome.subtitle", fallback: "Send a message and we’ll get back to you within 48 hours") /// Welcome to Message Center internal static let title = Localization.tr("Localizable", "message_center.welcome.title", fallback: "Welcome to Message Center") internal enum CheckMessages { @@ -433,12 +430,8 @@ internal enum Localization { internal enum Accessibility { /// Opens the file picker to attach media. internal static let hint = Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.hint", fallback: "Opens the file picker to attach media.") - } - } - internal enum FilePickerLabel { - internal enum Accessibility { /// File picker - internal static let label = Localization.tr("Localizable", "message_center.welcome.file_picker_label.accessibility.label", fallback: "File picker") + internal static let label = Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.label", fallback: "File picker") } } internal enum MessageTextView { diff --git a/GliaWidgets/Resources/en.lproj/Localizable.strings b/GliaWidgets/Resources/en.lproj/Localizable.strings index bb65d4288..ed8d95205 100644 --- a/GliaWidgets/Resources/en.lproj/Localizable.strings +++ b/GliaWidgets/Resources/en.lproj/Localizable.strings @@ -167,7 +167,6 @@ "general.you" = "You"; "gva.error_unsupported" = "This action is not currently supported on mobile."; "media.audio.name" = "Audio"; -"media.messaging.description" = "Send a message and we’ll get back to you \nwithin 48 hours"; "media.phone.name" = "Phone"; "media.text.name" = "Chat"; "media.video.name" = "Video"; @@ -179,9 +178,10 @@ "message_center.not_authenticated.message" = "We could not verify your authentication status."; "message_center.unavailable.message" = "The Message Center is currently unavailable. Please try again later."; "message_center.unavailable.title" = "Message Center Unavailable"; +"message_center.welcome.subtitle" = "Send a message and we’ll get back to you within 48 hours"; "message_center.welcome.check_messages.accessibility.hint" = "Navigates you to the chat transcript."; "message_center.welcome.file_picker.accessibility.hint" = "Opens the file picker to attach media."; -"message_center.welcome.file_picker_label.accessibility.label" = "File picker"; +"message_center.welcome.file_picker.accessibility.label" = "File picker"; "message_center.welcome.message_length_warning" = "The message cannot exceed 10000 characters."; "message_center.welcome.message_text_view.placeholder" = "Enter your message"; "message_center.welcome.message_title" = "Your message"; From 0fe8be749cf12f23efe46d473e55f89254bb5ec3 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Wed, 16 Aug 2023 13:31:05 +0300 Subject: [PATCH 11/40] Update strings in call screens The changes in this file were done partially. This is because there are some strings that are using parameters in the string which are replaces on runtime. These need to be evaluated to see if a backwards compatibility layer is needed for them or not, which is out of the scope of this task at the moment. MOB-2538 --- .../Sources/ViewModel/Call/CallViewModel.swift | 10 ++++------ .../Mocks/CallButtonBarStyle.Mock.swift | 16 ++++++---------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift index e20c27693..a742d4c8e 100644 --- a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift @@ -2,8 +2,6 @@ import Foundation import UIKit class CallViewModel: EngagementViewModel, ViewModel { - private typealias Strings = L10n.Call - var action: ((Action) -> Void)? var delegate: ((DelegateEvent) -> Void)? @@ -96,7 +94,7 @@ class CallViewModel: EngagementViewModel, ViewModel { case .engaged: showConnecting() - let operatorName = Strings.Operator.name.withOperatorName( + let operatorName = L10n.Call.Operator.name.withOperatorName( interactor.engagedOperator?.firstName ) @@ -139,7 +137,7 @@ class CallViewModel: EngagementViewModel, ViewModel { private func update(for callKind: CallKind) { switch callKind { case .audio: - action?(.setTitle(Strings.Audio.title)) + action?(.setTitle(Localization.Media.Audio.name)) action?(.setTopTextHidden(true)) case .video(let direction): switch direction { @@ -150,7 +148,7 @@ class CallViewModel: EngagementViewModel, ViewModel { action?(.setTopTextHidden(true)) } - action?(.setTitle(Strings.Video.title)) + action?(.setTitle(Localization.Media.Video.name)) } updateButtons() } @@ -391,7 +389,7 @@ extension CallViewModel { } private func onDurationChanged(_ duration: Int) { - let text = Strings.Connect.Connected.secondText.withCallDuration( + let text = L10n.Call.Connect.Connected.secondText.withCallDuration( duration.asDurationString ) action?(.setCallDurationText(text)) diff --git a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift index d94292f77..2f660e71a 100644 --- a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift @@ -43,12 +43,12 @@ extension CallButtonStyle.StateStyle { backgroundColor: ColorType = .fill(color: UIColor.white.withAlphaComponent(0.9)), image: UIImage = Asset.callChat.image, imageColor: ColorType = .fill(color: Color.baseDark), - title: String = L10n.Call.Buttons.Chat.title, + title: String = Localization.Media.Text.name, titleFont: UIFont = .systemFont(ofSize: 12, weight: .regular), titleColor: UIColor = Color.baseLight, textStyle: UIFont.TextStyle = .caption1, accessibility: Accessibility = .init( - label: L10n.Call.Accessibility.Buttons.Chat.Active.label + label: Localization.General.selected ) ) -> CallButtonStyle.StateStyle { return .init( @@ -67,13 +67,11 @@ extension CallButtonStyle.StateStyle { backgroundColor: ColorType = .fill(color: UIColor.black.withAlphaComponent(0.4)), image: UIImage = Asset.callChat.image, imageColor: ColorType = .fill(color: Color.baseLight), - title: String = L10n.Call.Buttons.Chat.title, + title: String = Localization.Media.Text.name, titleFont: UIFont = .systemFont(ofSize: 12, weight: .regular), titleColor: UIColor = Color.baseLight, textStyle: UIFont.TextStyle = .caption1, - accessibility: Accessibility = .init( - label: L10n.Call.Accessibility.Buttons.Chat.Inactive.label - ) + accessibility: Accessibility = .init(label: "") ) -> CallButtonStyle.StateStyle { return .init( backgroundColor: backgroundColor, @@ -91,13 +89,11 @@ extension CallButtonStyle.StateStyle { backgroundColor: ColorType = .fill(color: UIColor.black.withAlphaComponent(0.4)), image: UIImage = Asset.callChat.image, imageColor: ColorType = .fill(color: Color.baseLight), - title: String = L10n.Call.Buttons.Chat.title, + title: String = Localization.Media.Text.name, titleFont: UIFont = .systemFont(ofSize: 12, weight: .regular), titleColor: UIColor = Color.baseLight, textStyle: UIFont.TextStyle = .caption1, - accessibility: Accessibility = .init( - label: L10n.Call.Accessibility.Buttons.Chat.Inactive.label - ) + accessibility: Accessibility = .init(label: "") ) -> CallButtonStyle.StateStyle { return .init( backgroundColor: backgroundColor, From 53143b53261dc311643b1ec957fa3e114940c0c4 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Wed, 16 Aug 2023 13:32:21 +0300 Subject: [PATCH 12/40] Update strings in secure conversations welcome screen A couple of strings have been left untouched because they don't use secure conversations specific strings. They use chat strings. So these will be done in a future PR to avoid making the PR too big. MOB-2538 --- .../Theme+SecureConversationsWelcome.swift | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift index 6b25526b0..7b852ee38 100644 --- a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift +++ b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift @@ -2,7 +2,7 @@ import UIKit extension Theme { var secureConversationsWelcomeStyle: SecureConversations.WelcomeStyle { - typealias Welcome = L10n.MessageCenter.Welcome + typealias Welcome = Localization.MessageCenter.Welcome let chat = chatStyle var header = chat.header @@ -25,14 +25,14 @@ extension Theme { ) let checkMessagesButtonStyle = SecureConversations.WelcomeStyle.CheckMessagesButtonStyle( - title: Welcome.checkMessages, + title: Localization.MessageCenter.checkMessages, font: font.header2, textStyle: .title2, color: color.primary, accessibility: .init( isFontScalingEnabled: true, - label: Welcome.Accessibility.checkMessagesLabel, - hint: Welcome.Accessibility.checkMessagesHint + label: Localization.MessageCenter.checkMessages, + hint: Welcome.CheckMessages.Accessibility.hint ) ) @@ -45,7 +45,7 @@ extension Theme { ) let messageTextViewNormalStyle = SecureConversations.WelcomeStyle.MessageTextViewNormalStyle( - placeholderText: Welcome.messageTextViewNormal, + placeholderText: Welcome.MessageTextView.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -59,7 +59,7 @@ extension Theme { ) let messageTextViewActiveStyle = SecureConversations.WelcomeStyle.MessageTextViewActiveStyle( - placeholderText: Welcome.messageTextViewActive, + placeholderText: Welcome.MessageTextView.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -73,7 +73,7 @@ extension Theme { ) let messageTextViewDisabledStyle = SecureConversations.WelcomeStyle.MessageTextViewDisabledStyle( - placeholderText: Welcome.messageTextViewDisabled, + placeholderText: Welcome.MessageTextView.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -93,7 +93,7 @@ extension Theme { ) let sendButtonEnabledStyle = SecureConversations.WelcomeStyle.SendButtonEnabledStyle( - title: Welcome.sendEnabled, + title: Localization.Chat.Input.send, font: font.bodyText, textStyle: .body, textColor: color.baseLight, @@ -103,13 +103,13 @@ extension Theme { cornerRadius: 4, accessibility: .init( isFontScalingEnabled: true, - label: Welcome.Accessibility.sendLabel, - hint: Welcome.Accessibility.sendHint + label: Localization.Chat.Input.send, + hint: Welcome.Send.Accessibility.hint ) ) let sendButtonDisabledStyle = SecureConversations.WelcomeStyle.SendButtonDisabledStyle( - title: Welcome.sendDisabled, + title: Localization.Chat.Input.send, font: font.bodyText, textStyle: .body, textColor: .disabledTitle, @@ -119,13 +119,13 @@ extension Theme { cornerRadius: 4, accessibility: .init( isFontScalingEnabled: true, - label: Welcome.Accessibility.sendLabel, - hint: Welcome.Accessibility.sendHint + label: Localization.Chat.Input.send, + hint: Welcome.Send.Accessibility.hint ) ) let sendButtonLoadingStyle = SecureConversations.WelcomeStyle.SendButtonLoadingStyle( - title: Welcome.sendLoading, + title: Localization.Chat.Input.send, font: font.bodyText, textStyle: .body, textColor: .disabledTitle, @@ -136,8 +136,8 @@ extension Theme { cornerRadius: 4, accessibility: .init( isFontScalingEnabled: true, - label: Welcome.Accessibility.sendLabel, - hint: Welcome.Accessibility.sendHint + label: Localization.Chat.Input.send, + hint: Welcome.Send.Accessibility.hint ) ) @@ -161,8 +161,8 @@ extension Theme { disabledColor: .lightGray, accessibility: .init( isFontScalingEnabled: true, - accessibilityLabel: Welcome.Accessibility.filePickerLabel, - accessibilityHint: Welcome.Accessibility.filePickerHint + accessibilityLabel: Welcome.FilePicker.Accessibility.label, + accessibilityHint: Welcome.FilePicker.Accessibility.hint ) ) @@ -280,7 +280,7 @@ extension Theme { return .init( header: header, - headerTitle: Welcome.header, + headerTitle: Localization.MessageCenter.header, welcomeTitleStyle: welcomeTitleStyle, titleImageStyle: titleImageStyle, welcomeSubtitleStyle: welcomeSubtitleStyle, From 8b618388b680434a3402d3fe2abb72a4227bf6f3 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Mon, 21 Aug 2023 08:42:31 +0300 Subject: [PATCH 13/40] Replace old strings with new strings in some views This time, strings in screen sharing, alert, call, and survey mocks were changed. Also a string that was previously missing was added. MOB-2538 --- GliaWidgets/Localization.swift | 20 +- .../Public/Configuration/Configuration.swift | 2 +- .../Resources/en.lproj/Localizable.strings | 8 +- .../View/ScreenSharingView.swift | 4 +- .../Extensions/String+TemplateString.swift | 2 +- GliaWidgets/Sources/Theme/Theme+Alert.swift | 13 +- GliaWidgets/Sources/Theme/Theme+Call.swift | 188 ++++++++---------- .../Survey.ViewController.Props.Mock.swift | 6 +- .../Survey/Survey.ViewController.Props.swift | 14 +- .../Survey/SurveyViewController.View.swift | 6 +- .../Mocks/ScreenSharingViewStyle+Mock.swift | 2 +- .../VideoCall/Mocks/HeaderStyle.Mock.swift | 2 +- 12 files changed, 124 insertions(+), 143 deletions(-) diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index a28bc522e..1237f5133 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -258,8 +258,8 @@ internal enum Localization { /// {operatorName} has offered you to upgrade internal static let offerUpgrade = Localization.tr("Localizable", "engagement.offer_upgrade", fallback: "{operatorName} has offered you to upgrade") internal enum Connect { - /// We are here to help - internal static let placeholder = Localization.tr("Localizable", "engagement.connect.placeholder", fallback: "We are here to help") + /// We are here to help! + internal static let placeholder = Localization.tr("Localizable", "engagement.connect.placeholder", fallback: "We are here to help!") /// Connecting with {operatorName} internal static let with = Localization.tr("Localizable", "engagement.connect.with", fallback: "Connecting with {operatorName}") } @@ -302,6 +302,8 @@ internal enum Localization { internal enum QueueWait { /// You can continue browsing and we will connect you automatically. internal static let message = Localization.tr("Localizable", "engagement.queue_wait.message", fallback: "You can continue browsing and we will connect you automatically.") + /// (By default your video will be off) + internal static let videoNotice = Localization.tr("Localizable", "engagement.queue_wait.video_notice", fallback: "(By default your video will be off)") } internal enum SecureMessaging { /// Messaging @@ -347,8 +349,8 @@ internal enum Localization { internal static let ok = Localization.tr("Localizable", "general.ok", fallback: "Ok") /// Open internal static let `open` = Localization.tr("Localizable", "general.open", fallback: "Open") - /// Powered by Glia - internal static let poweredBy = Localization.tr("Localizable", "general.powered_by", fallback: "Powered by Glia") + /// Powered by + internal static let poweredBy = Localization.tr("Localizable", "general.powered_by", fallback: "Powered by") /// Retry internal static let retry = Localization.tr("Localizable", "general.retry", fallback: "Retry") /// Selected @@ -448,12 +450,18 @@ internal enum Localization { } internal enum ScreenSharing { internal enum VisitorScreen { - /// End screen sharing - internal static let end = Localization.tr("Localizable", "screen_sharing.visitor_screen.end", fallback: "End screen sharing") + /// End Screen Sharing + internal static let end = Localization.tr("Localizable", "screen_sharing.visitor_screen.end", fallback: "End Screen Sharing") internal enum Disclaimer { /// You are about to share your screen internal static let title = Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.title", fallback: "You are about to share your screen") } + internal enum End { + internal enum Accessibility { + /// Ends screen sharing + internal static let hint = Localization.tr("Localizable", "screen_sharing.visitor_screen.end.accessibility.hint", fallback: "Ends screen sharing") + } + } } } internal enum Screensharing { diff --git a/GliaWidgets/Public/Configuration/Configuration.swift b/GliaWidgets/Public/Configuration/Configuration.swift index 718719406..84f688404 100644 --- a/GliaWidgets/Public/Configuration/Configuration.swift +++ b/GliaWidgets/Public/Configuration/Configuration.swift @@ -32,7 +32,7 @@ public struct Configuration { visitorContext: VisitorContext? = nil, pushNotifications: PushNotifications = .disabled, isWhiteLabelApp: Bool = false, - companyName: String = L10n.Chat.Connect.Queue.firstText + companyName: String = "" ) { self.authorizationMethod = authorizationMethod self.environment = environment diff --git a/GliaWidgets/Resources/en.lproj/Localizable.strings b/GliaWidgets/Resources/en.lproj/Localizable.strings index ed8d95205..ce2a4a555 100644 --- a/GliaWidgets/Resources/en.lproj/Localizable.strings +++ b/GliaWidgets/Resources/en.lproj/Localizable.strings @@ -124,7 +124,7 @@ "chat.upgrade.audio.text" = "Upgraded to Audio Call"; "chat.upgrade.video.text" = "Upgraded to Video Call"; "chat.upload.remove.accessibility.label" = "Remove upload"; -"engagement.connect.placeholder" = "We are here to help"; +"engagement.connect.placeholder" = "We are here to help!"; "engagement.connect.with" = "Connecting with {operatorName}"; "engagement.default_operator_name" = "Operator"; "engagement.end.confirmation.header" = "End Engagement?"; @@ -139,6 +139,7 @@ "engagement.queue_leave.message" = "You will lose your place in the queue."; "engagement.queue_reconnection_failed.try_again" = "Please try again."; "engagement.queue_transferring.message" = "Transferring"; +"engagement.queue_wait.video_notice" = "(By default your video will be off)"; "engagement.queue_wait.message" = "You can continue browsing and we will connect you automatically."; "engagement.secure_messaging.title" = "Messaging"; "error.general" = "Something went wrong"; @@ -158,7 +159,7 @@ "general.no" = "No"; "general.ok" = "Ok"; "general.open" = "Open"; -"general.powered_by" = "Powered by Glia"; +"general.powered_by" = "Powered by"; "general.retry" = "Retry"; "general.selected" = "Selected"; "general.submit" = "Submit"; @@ -188,7 +189,8 @@ "message_center.welcome.send.accessibility.hint" = "Sends a secure message."; "message_center.welcome.title" = "Welcome to Message Center"; "screen_sharing.visitor_screen.disclaimer.title" = "You are about to share your screen"; -"screen_sharing.visitor_screen.end" = "End screen sharing"; +"screen_sharing.visitor_screen.end" = "End Screen Sharing"; +"screen_sharing.visitor_screen.end.accessibility.hint" = "Ends screen sharing"; "screensharing.visitor_screen.disclaimer.info" = "Depending on your selection, your entire screen might be shared with the operator, not just the application window."; "send_message.send" = "Send message"; "send_message.sending" = "Sending…"; diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift index f6f985d41..039f49cc3 100644 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift @@ -46,8 +46,8 @@ extension CallVisualizer { $0.titleLabel?.numberOfLines = 0 $0.titleLabel?.translatesAutoresizingMaskIntoConstraints = false $0.accessibilityIdentifier = "end_screen_sharing_button" - $0.accessibilityLabel = L10n.CallVisualizer.ScreenSharing.Accessibility.buttonLabel - $0.accessibilityHint = L10n.CallVisualizer.ScreenSharing.Accessibility.buttonHint + $0.accessibilityLabel = Localization.ScreenSharing.VisitorScreen.end + $0.accessibilityHint = Localization.ScreenSharing.VisitorScreen.End.Accessibility.hint } private lazy var contentStackView = UIStackView.make( .vertical, diff --git a/GliaWidgets/Sources/Extensions/String+TemplateString.swift b/GliaWidgets/Sources/Extensions/String+TemplateString.swift index 4112b220d..ea9315ffb 100644 --- a/GliaWidgets/Sources/Extensions/String+TemplateString.swift +++ b/GliaWidgets/Sources/Extensions/String+TemplateString.swift @@ -1,6 +1,6 @@ extension String { func withOperatorName(_ name: String?) -> String { - let name = name ?? L10n.operator + let name = name ?? Localization.Engagement.defaultOperatorName return replacingOccurrences(of: "{operatorName}", with: name) } diff --git a/GliaWidgets/Sources/Theme/Theme+Alert.swift b/GliaWidgets/Sources/Theme/Theme+Alert.swift index f3883c527..da3d0f6eb 100644 --- a/GliaWidgets/Sources/Theme/Theme+Alert.swift +++ b/GliaWidgets/Sources/Theme/Theme+Alert.swift @@ -1,30 +1,27 @@ extension Theme { var alertStyle: AlertStyle { - typealias Alert = L10n.Alert - typealias Accessibility = Alert.Accessibility - let negativeAction = ActionButtonStyle( - title: Alert.Action.no, + title: Localization.General.no, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.systemNegative), accessibility: .init( - label: Accessibility.Action.no, + label: Localization.General.no, isFontScalingEnabled: true ) ) let positiveAction = ActionButtonStyle( - title: Alert.Action.yes, + title: Localization.General.yes, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.primary), accessibility: .init( - label: Accessibility.Action.yes, + label: Localization.General.yes, isFontScalingEnabled: true ) ) let poweredBy = PoweredByStyle( - text: L10n.poweredBy, + text: Localization.General.poweredBy, font: font.caption, accessibility: .init(isFontScalingEnabled: true) ) diff --git a/GliaWidgets/Sources/Theme/Theme+Call.swift b/GliaWidgets/Sources/Theme/Theme+Call.swift index 14bc44232..8c98aa55f 100644 --- a/GliaWidgets/Sources/Theme/Theme+Call.swift +++ b/GliaWidgets/Sources/Theme/Theme+Call.swift @@ -2,9 +2,6 @@ import UIKit extension Theme { var callStyle: CallStyle { - typealias Call = L10n.Call - typealias Accessibility = Call.Accessibility - let onHoldOverlay = OnHoldOverlayStyle( image: Asset.callOnHold.image, imageColor: .fill(color: .white), @@ -14,25 +11,25 @@ extension Theme { image: Asset.back.image, color: color.baseLight, accessibility: .init( - label: Accessibility.Header.BackButton.label, - hint: Accessibility.Header.BackButton.hint + label: Localization.General.back, + hint: Localization.Call.Header.Close.Button.Accessibility.hint ) ) let closeButton = HeaderButtonStyle( image: Asset.close.image, color: color.baseLight, accessibility: .init( - label: Accessibility.Header.CloseButton.label, - hint: Accessibility.Header.CloseButton.hint + label: Localization.General.close, + hint: "" ) ) let endButton = ActionButtonStyle( - title: Call.EndButton.title, + title: Localization.General.end, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.systemNegative), accessibility: .init( - label: Accessibility.Header.EndButton.label, + label: Localization.General.end, isFontScalingEnabled: true ) ) @@ -40,8 +37,8 @@ extension Theme { image: Asset.startScreenShare.image, color: color.baseLight, accessibility: .init( - label: Accessibility.Header.EndScreenShareButton.label, - hint: Accessibility.Header.EndScreenShareButton.hint + label: Localization.General.end, + hint: "" ) ) let header = HeaderStyle( @@ -66,72 +63,72 @@ extension Theme { animationColor: .lightGray, onHoldOverlay: onHoldOverlay, accessibility: .init( - label: Accessibility.Operator.Avatar.label, - hint: Accessibility.Operator.Avatar.hint + label: Localization.Call.Operator.Avatar.Accessibility.label, + hint: Localization.Call.Operator.Avatar.Accessibility.hint ) ) let queue = ConnectStatusStyle( - firstText: Call.Connect.Queue.firstText, + firstText: Localization.General.companyName, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: Call.Connect.Queue.secondText, + secondText: Localization.Engagement.Connect.placeholder, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Accessibility.Connect.Queue.FirstText.hint, + firstTextHint: Localization.Call.Connect.FirstText.Accessibility.hint, secondTextHint: nil, isFontScalingEnabled: true ) ) let connecting = ConnectStatusStyle( - firstText: Call.Connect.Connecting.firstText, + firstText: Localization.Engagement.Connect.with, firstTextFont: font.header2, firstTextFontColor: color.baseLight, firstTextStyle: .title2, - secondText: Call.Connect.Connecting.secondText, + secondText: "", secondTextFont: font.header2, secondTextFontColor: color.baseLight, secondTextStyle: .title2, accessibility: .init( - firstTextHint: Accessibility.Connect.Connecting.FirstText.hint, + firstTextHint: Localization.Call.Connect.FirstText.Accessibility.hint, secondTextHint: nil, isFontScalingEnabled: true ) ) let connected = ConnectStatusStyle( - firstText: Call.Connect.Connected.firstText, + firstText: L10n.Call.Connect.Connected.firstText, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: Call.Connect.Connected.secondText, + secondText: L10n.Call.Connect.Connected.secondText, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Accessibility.Connect.Connected.FirstText.hint, - secondTextHint: Accessibility.Connect.Connected.SecondText.hint, + firstTextHint: Localization.Call.Connect.FirstText.Accessibility.hint, + secondTextHint: Localization.Call.Connect.SecondText.Accessibility.hint, isFontScalingEnabled: true ) ) let onHold = ConnectStatusStyle( - firstText: Call.Connect.Connected.firstText, + firstText: L10n.Call.Connect.Connected.firstText, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: Call.Connect.Connected.secondText, + secondText: L10n.Call.Connect.Connected.secondText, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Accessibility.Connect.Connected.FirstText.hint, + firstTextHint: Localization.Call.Connect.FirstText.Accessibility.hint, secondTextHint: nil, isFontScalingEnabled: true ) ) let transferring = ConnectStatusStyle( - firstText: Call.Connect.Transferring.firstText, + firstText: Localization.Engagement.QueueTransferring.message, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, @@ -149,9 +146,9 @@ extension Theme { onHold: onHold ) let onHoldStyle = CallStyle.OnHoldStyle( - onHoldText: Call.OnHold.topText, - descriptionText: Call.OnHold.bottomText, - localVideoStreamLabelText: Call.OnHold.localVideoStreamLabelText, + onHoldText: Localization.Call.onHold, + descriptionText: Localization.Call.OnHold.bottomText, + localVideoStreamLabelText: Localization.General.you, localVideoStreamLabelFont: font.mediumSubtitle2, localVideoStreamLabelColor: color.baseLight ) @@ -161,35 +158,32 @@ extension Theme { connect: connect, backgroundColor: .fill(color: .white), preferredStatusBarStyle: .lightContent, - audioTitle: Call.Audio.title, - videoTitle: Call.Video.title, - operatorName: Call.Operator.name, + audioTitle: Localization.Media.Audio.name, + videoTitle: Localization.Media.Video.name, + operatorName: L10n.Call.Operator.name, operatorNameFont: font.header1, operatorNameColor: color.baseLight, durationFont: font.bodyText, durationColor: color.baseLight, - topText: Call.topText, + topText: Localization.Engagement.QueueWait.videoNotice, topTextFont: font.subtitle, topTextColor: color.baseLight, - bottomText: Call.bottomText, + bottomText: Localization.Engagement.QueueWait.message, bottomTextFont: font.bodyText, bottomTextColor: color.baseLight, buttonBar: buttonBarStyle, onHoldStyle: onHoldStyle, accessibility: .init( - operatorNameHint: Accessibility.OperatorName.hint, - durationHint: Accessibility.CallDuration.hint, - localVideoLabel: Accessibility.Video.Visitor.label, - remoteVideoLabel: Accessibility.Video.Operator.label, + operatorNameHint: Localization.Call.Connect.FirstText.Accessibility.hint, + durationHint: Localization.Call.Connect.SecondText.Accessibility.hint, + localVideoLabel: Localization.Call.Video.Visitor.Accessibility.label, + remoteVideoLabel: Localization.Call.Video.Operator.Accessibility.label, isFontScalingEnabled: true ) ) } private var buttonBarStyle: CallButtonBarStyle { - typealias Buttons = L10n.Call.Buttons - typealias Accessibility = L10n.Call.Accessibility - let activeBackgroundColor: ColorType = .fill(color: UIColor.white.withAlphaComponent(0.9)) let inactiveBackgroundColor: ColorType = .fill(color: UIColor.black.withAlphaComponent(0.4)) let activeImageColor: ColorType = .fill(color: color.baseDark) @@ -204,42 +198,38 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callChat.image, imageColor: activeImageColor, - title: Buttons.Chat.title, + title: Localization.Media.Text.name, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, accessibility: .init( - label: Accessibility.Buttons.Chat.Active.label + label: Localization.General.selected ) ), inactive: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callChat.image, imageColor: inactiveImageColor, - title: Buttons.Chat.title, + title: Localization.Media.Text.name, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Chat.Inactive.label - ) + accessibility: .init(label: "") ), selected: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callChat.image, imageColor: inactiveImageColor, - title: Buttons.Chat.title, + title: Localization.Media.Text.name, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Chat.Inactive.label - ) + accessibility: .init(label: "") ), accessibility: .init( - singleItemBadgeValue: Accessibility.Buttons.Chat.BadgeValue.singleItem, - multipleItemsBadgeValue: Accessibility.Buttons.Chat.BadgeValue.multipleItems, - titleAndBadgeValue: Accessibility.Buttons.Chat.titleAndBadgeValue, + singleItemBadgeValue: Localization.Call.Buttons.Chat.BadgeValue.SingleItem.Accessibility.label, + multipleItemsBadgeValue: Localization.Call.Buttons.Chat.BadgeValue.MultipleItems.Accessibility.label, + titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Chat.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -248,42 +238,38 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callVideoActive.image, imageColor: activeImageColor, - title: Buttons.Video.title, + title: Localization.Media.Video.name, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, accessibility: .init( - label: Accessibility.Buttons.Video.Active.label + label: Localization.General.selected ) ), inactive: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callVideoInactive.image, imageColor: inactiveImageColor, - title: Buttons.Video.title, + title: Localization.Media.Video.name, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Video.Inactive.label - ) + accessibility: .init(label: "") ), selected: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callVideoInactive.image, imageColor: inactiveImageColor, - title: Buttons.Video.title, + title: Localization.Media.Video.name, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Video.Inactive.label - ) + accessibility: .init(label: "") ), accessibility: .init( - singleItemBadgeValue: Accessibility.Buttons.Video.BadgeValue.singleItem, - multipleItemsBadgeValue: Accessibility.Buttons.Video.BadgeValue.multipleItems, - titleAndBadgeValue: Accessibility.Buttons.Video.titleAndBadgeValue, + singleItemBadgeValue: "", + multipleItemsBadgeValue: "", + titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Video.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -292,42 +278,38 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callMuteActive.image, imageColor: activeImageColor, - title: Buttons.Mute.Active.title, + title: Localization.Call.Button.unmute, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, accessibility: .init( - label: Accessibility.Buttons.Mute.Active.label + label: Localization.General.selected ) ), inactive: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callMuteInactive.image, imageColor: inactiveImageColor, - title: Buttons.Mute.Inactive.title, + title: Localization.Call.Button.mute, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Mute.Inactive.label - ) + accessibility: .init(label: "") ), selected: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callMuteInactive.image, imageColor: inactiveImageColor, - title: Buttons.Mute.Inactive.title, + title: Localization.Call.Button.mute, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Mute.Inactive.label - ) + accessibility: .init(label: "") ), accessibility: .init( - singleItemBadgeValue: Accessibility.Buttons.Mute.BadgeValue.singleItem, - multipleItemsBadgeValue: Accessibility.Buttons.Mute.BadgeValue.multipleItems, - titleAndBadgeValue: Accessibility.Buttons.Mute.titleAndBadgeValue, + singleItemBadgeValue: "", + multipleItemsBadgeValue: "", + titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Mute.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -336,42 +318,38 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callSpeakerActive.image, imageColor: activeImageColor, - title: Buttons.Speaker.title, + title: Localization.Call.Button.speaker, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, accessibility: .init( - label: Accessibility.Buttons.Speaker.Active.label + label: Localization.General.selected ) ), inactive: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callSpeakerInactive.image, imageColor: inactiveImageColor, - title: Buttons.Speaker.title, + title: Localization.Call.Button.speaker, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Speaker.Inactive.label - ) + accessibility: .init(label: "") ), selected: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callSpeakerInactive.image, imageColor: inactiveImageColor, - title: Buttons.Speaker.title, + title: Localization.Call.Button.speaker, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Speaker.Inactive.label - ) + accessibility: .init(label: "") ), accessibility: .init( - singleItemBadgeValue: Accessibility.Buttons.Speaker.BadgeValue.singleItem, - multipleItemsBadgeValue: Accessibility.Buttons.Speaker.BadgeValue.multipleItems, - titleAndBadgeValue: Accessibility.Buttons.Speaker.titleAndBadgeValue, + singleItemBadgeValue: "", + multipleItemsBadgeValue: "", + titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Speaker.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -380,42 +358,38 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callMiminize.image, imageColor: activeImageColor, - title: Buttons.Minimize.title, + title: Localization.Engagement.minimizeVideoButton, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, accessibility: .init( - label: Accessibility.Buttons.Minimize.Active.label + label: Localization.General.selected ) ), inactive: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callMiminize.image, imageColor: inactiveImageColor, - title: Buttons.Minimize.title, + title: Localization.Engagement.minimizeVideoButton, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Minimize.Inactive.label - ) + accessibility: .init(label: "") ), selected: CallButtonStyle.StateStyle( backgroundColor: inactiveBackgroundColor, image: Asset.callMiminize.image, imageColor: inactiveImageColor, - title: Buttons.Minimize.title, + title: Localization.Engagement.minimizeVideoButton, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, - accessibility: .init( - label: Accessibility.Buttons.Minimize.Inactive.label - ) + accessibility: .init(label: "") ), accessibility: .init( - singleItemBadgeValue: Accessibility.Buttons.Minimize.BadgeValue.singleItem, - multipleItemsBadgeValue: Accessibility.Buttons.Minimize.BadgeValue.multipleItems, - titleAndBadgeValue: Accessibility.Buttons.Minimize.titleAndBadgeValue, + singleItemBadgeValue: "", + multipleItemsBadgeValue: "", + titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Minimize.titleAndBadgeValue, isFontScalingEnabled: true ) ) diff --git a/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift b/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift index 3b89f2a80..f28070a4c 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Mocks/Survey.ViewController.Props.Mock.swift @@ -26,7 +26,7 @@ extension Survey.ViewController.Props { )), makeInputPropsMock(), makeBooleanPropsMock(selectedOption: .init( - name: L10n.Survey.Action.yes, + name: Localization.General.yes, value: true )), makeSinglePropsMock(selectedOption: .init( @@ -90,8 +90,8 @@ private extension Survey.ViewController.Props { accessibility: .init(value: "Required") ) props.options = [ - .init(name: L10n.Survey.Action.yes, value: true), - .init(name: L10n.Survey.Action.no, value: false) + .init(name: Localization.General.yes, value: true), + .init(name: Localization.General.no, value: false) ].compactMap { $0 } props.selected = selectedOption return props diff --git a/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift b/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift index 4629d89ba..b29e5239e 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift @@ -123,7 +123,7 @@ extension Survey.ViewController.Props { ) -> Survey.ScaleQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? L10n.Survey.Accessibility.Question.Title.value + ? Localization.Survey.Question.Title.Accessibility.label : nil var scaleProps = Survey.ScaleQuestionView.Props( @@ -163,7 +163,7 @@ extension Survey.ViewController.Props { ) -> Survey.BooleanQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? L10n.Survey.Accessibility.Question.Title.value + ? Localization.Survey.Question.Title.Accessibility.label : nil var booleanProps = Survey.BooleanQuestionView.Props( @@ -183,8 +183,8 @@ extension Survey.ViewController.Props { updateProps(newViewControllerProps) } booleanProps.options = [ - .init(name: L10n.Survey.Action.yes, value: true, select: handleBooleanOptionSelection), - .init(name: L10n.Survey.Action.no, value: false, select: handleBooleanOptionSelection) + .init(name: Localization.General.yes, value: true, select: handleBooleanOptionSelection), + .init(name: Localization.General.no, value: false, select: handleBooleanOptionSelection) ] return booleanProps @@ -200,7 +200,7 @@ extension Survey.ViewController.Props { ) -> Survey.SingleChoiceQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? L10n.Survey.Accessibility.Question.Title.value + ? Localization.Survey.Question.Title.Accessibility.label : nil var scaleProps = Survey.SingleChoiceQuestionView.Props( @@ -241,7 +241,7 @@ extension Survey.ViewController.Props { ) -> Survey.InputQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? L10n.Survey.Accessibility.Question.Title.value + ? Localization.Survey.Question.Title.Accessibility.label : nil var inputProps = Survey.InputQuestionView.Props( @@ -250,7 +250,7 @@ extension Survey.ViewController.Props { isRequired: sdkQuestion.required, accessibility: .init( titleValue: accessibilityValue, - fieldHint: L10n.Survey.Accessibility.Question.TextField.hint + fieldHint: Localization.Survey.Question.TextField.Accessibility.hint ) ) inputProps.textDidChange = { newValue in diff --git a/GliaWidgets/Sources/ViewController/Survey/SurveyViewController.View.swift b/GliaWidgets/Sources/ViewController/Survey/SurveyViewController.View.swift index 670d027f0..f10ee44be 100644 --- a/GliaWidgets/Sources/ViewController/Survey/SurveyViewController.View.swift +++ b/GliaWidgets/Sources/ViewController/Survey/SurveyViewController.View.swift @@ -30,7 +30,7 @@ extension Survey { $0.layer.shadowRadius = 8 } let cancelButton = UIButton(type: .custom).make { - $0.setTitle(L10n.Survey.Action.cancel, for: .normal) + $0.setTitle(Localization.General.cancel, for: .normal) $0.titleLabel?.numberOfLines = 0 // Using `byWordWrapping` prevents button text // from getting truncated, for example for large @@ -38,7 +38,7 @@ extension Survey { $0.titleLabel?.lineBreakMode = .byWordWrapping } let submitButton = UIButton(type: .custom).make { - $0.setTitle(L10n.Survey.Action.submit, for: .normal) + $0.setTitle(Localization.General.submit, for: .normal) $0.titleLabel?.numberOfLines = 0 $0.titleLabel?.lineBreakMode = .byWordWrapping } @@ -201,7 +201,7 @@ extension NSAttributedString { if isRequired { mutableString.append( .init( - string: L10n.Survey.Question.Title.asterisk, + string: "*", attributes: [ .foregroundColor: UIColor.red, .font: font diff --git a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift b/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift index 98fabed61..a7bead115 100644 --- a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift @@ -11,7 +11,7 @@ extension ScreenSharingViewStyle { return ScreenSharingViewStyle( title: title, header: .mock(), - messageText: L10n.CallVisualizer.ScreenSharing.message, + messageText: Localization.CallVisualizer.ScreenSharing.message, messageTextFont: messageTextFont, messageTextColor: Color.baseDark, buttonStyle: .mock(titleFont: buttonTitleFont), diff --git a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift index b40ba6765..17704b310 100644 --- a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift @@ -36,7 +36,7 @@ extension HeaderButtonStyle { extension ActionButtonStyle { static func mock( - title: String = L10n.CallVisualizer.ScreenSharing.Button.title, + title: String = Localization.ScreenSharing.VisitorScreen.end, titleFont: UIFont = .systemFont(ofSize: 16, weight: .regular), titleColor: UIColor = .white, backgroundColor: ColorType = .fill(color: Color.systemNegative), From fa04fc7968bbee1537a15513cd589609f58614cd Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Thu, 24 Aug 2023 16:30:06 +0300 Subject: [PATCH 14/40] Replace old strings in chat, bubble, and alert functionality Also some strings have been changed as part of several discussions, so they have been updated here. MOB-2538 --- GliaWidgets/Localization.swift | 116 ++++++++++-- .../Resources/en.lproj/Localizable.strings | 33 +++- .../Survey/Theme.Survey.ValidationError.swift | 4 +- .../Theme/Theme+AlertConfiguration.swift | 110 ++++++------ GliaWidgets/Sources/Theme/Theme+Call.swift | 4 +- GliaWidgets/Sources/Theme/Theme+Chat.swift | 169 ++++++++---------- .../Sources/Theme/Theme+MinimizedBubble.swift | 4 +- 7 files changed, 272 insertions(+), 168 deletions(-) diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index 1237f5133..8def76126 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -68,11 +68,11 @@ internal enum Localization { } } internal enum Header { - internal enum Close { + internal enum Back { internal enum Button { internal enum Accessibility { /// Activates minimize. - internal static let hint = Localization.tr("Localizable", "call.header.close.button.accessibility.hint", fallback: "Activates minimize.") + internal static let hint = Localization.tr("Localizable", "call.header.back.button.accessibility.hint", fallback: "Activates minimize.") } } } @@ -159,19 +159,45 @@ internal enum Localization { internal static let operatorJoined = Localization.tr("Localizable", "chat.operator_joined", fallback: "{operatorName} has joined the conversation.") /// New Messages internal static let unreadMessageDivider = Localization.tr("Localizable", "chat.unread_message_divider", fallback: "New Messages") - internal enum Attachement { + internal enum Attachment { /// Photo Library - internal static let photoLibrary = Localization.tr("Localizable", "chat.attachement.photo_library", fallback: "Photo Library") + internal static let photoLibrary = Localization.tr("Localizable", "chat.attachment.photo_library", fallback: "Photo Library") /// Take Photo or Video - internal static let takePhoto = Localization.tr("Localizable", "chat.attachement.take_photo", fallback: "Take Photo or Video") + internal static let takePhoto = Localization.tr("Localizable", "chat.attachment.take_photo", fallback: "Take Photo or Video") + internal enum Message { + internal enum Accessibility { + /// Attachment from {fileSender} + internal static let label = Localization.tr("Localizable", "chat.attachment.message.accessibility.label", fallback: "Attachment from {fileSender}") + } + } internal enum Upload { /// Invalid file type! - internal static let unsupportedFile = Localization.tr("Localizable", "chat.attachement.upload.unsupported_file", fallback: "Invalid file type!") + internal static let unsupportedFile = Localization.tr("Localizable", "chat.attachment.upload.unsupported_file", fallback: "Invalid file type!") + } + } + internal enum ChoiceCard { + internal enum Button { + internal enum Disabled { + internal enum Accessibility { + /// Disabled + internal static let label = Localization.tr("Localizable", "chat.choice_card.button.disabled.accessibility.label", fallback: "Disabled") + } + } + } + internal enum Image { + internal enum Accessibility { + /// Choice card + internal static let label = Localization.tr("Localizable", "chat.choice_card.image.accessibility.label", fallback: "Choice card") + } } } internal enum Download { + /// Download + internal static let download = Localization.tr("Localizable", "chat.download.download", fallback: "Download") /// Downloading file… internal static let downloading = Localization.tr("Localizable", "chat.download.downloading", fallback: "Downloading file…") + /// Download failed + internal static let failed = Localization.tr("Localizable", "chat.download.failed", fallback: "Download failed") } internal enum Duration { internal enum Accessibility { @@ -187,8 +213,12 @@ internal enum Localization { internal enum Upload { /// Uploading failed internal static let failed = Localization.tr("Localizable", "chat.file.upload.failed", fallback: "Uploading failed") + /// Network error. + internal static let genericError = Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Network error.") /// Uploading file… internal static let inProgress = Localization.tr("Localizable", "chat.file.upload.in_progress", fallback: "Uploading file…") + /// Network error. + internal static let networkError = Localization.tr("Localizable", "chat.file.upload.network_error", fallback: "Network error.") /// Checking safety of the file… internal static let scanning = Localization.tr("Localizable", "chat.file.upload.scanning", fallback: "Checking safety of the file…") /// Ready to send @@ -202,6 +232,8 @@ internal enum Localization { internal static let send = Localization.tr("Localizable", "chat.input.send", fallback: "Send") } internal enum Message { + /// Tap on the answer above + internal static let choiceCardPlaceholder = Localization.tr("Localizable", "chat.message.choice_card_placeholder", fallback: "Tap on the answer above") /// Send a message to start chatting internal static let startEngagementPlaceholder = Localization.tr("Localizable", "chat.message.start_engagement_placeholder", fallback: "Send a message to start chatting") internal enum Unread { @@ -230,6 +262,12 @@ internal enum Localization { internal static let delivered = Localization.tr("Localizable", "chat.status.delivered", fallback: "Delivered") /// Operator typing internal static let typing = Localization.tr("Localizable", "chat.status.typing", fallback: "Operator typing") + internal enum Typing { + internal enum Accessibility { + /// {operatorName} is typing + internal static let label = Localization.tr("Localizable", "chat.status.typing.accessibility.label", fallback: "{operatorName} is typing") + } + } } internal enum Upgrade { internal enum Audio { @@ -257,6 +295,34 @@ internal enum Localization { internal static let minimizeVideoButton = Localization.tr("Localizable", "engagement.minimize_video_button", fallback: "Minimize") /// {operatorName} has offered you to upgrade internal static let offerUpgrade = Localization.tr("Localizable", "engagement.offer_upgrade", fallback: "{operatorName} has offered you to upgrade") + internal enum Alert { + internal enum Camera { + /// Unable to access camera + internal static let header = Localization.tr("Localizable", "engagement.alert.camera.header", fallback: "Unable to access camera") + } + internal enum MediaSource { + /// Unable to access media source + internal static let header = Localization.tr("Localizable", "engagement.alert.media_source.header", fallback: "Unable to access media source") + } + internal enum Microphone { + /// Unable to access microphone + internal static let header = Localization.tr("Localizable", "engagement.alert.microphone.header", fallback: "Unable to access microphone") + } + internal enum ScreenSharing { + internal enum Start { + /// {operatorName} has asked you to share your screen + internal static let header = Localization.tr("Localizable", "engagement.alert.screen_sharing.start.header", fallback: "{operatorName} has asked you to share your screen") + /// {operatorName} would like to see the screen of your device + internal static let message = Localization.tr("Localizable", "engagement.alert.screen_sharing.start.message", fallback: "{operatorName} would like to see the screen of your device") + } + internal enum Stop { + /// Stop screen sharing? + internal static let header = Localization.tr("Localizable", "engagement.alert.screen_sharing.stop.header", fallback: "Stop screen sharing?") + /// Are you sure you want to stop sharing your screen? + internal static let message = Localization.tr("Localizable", "engagement.alert.screen_sharing.stop.message", fallback: "Are you sure you want to stop sharing your screen?") + } + } + } internal enum Connect { /// We are here to help! internal static let placeholder = Localization.tr("Localizable", "engagement.connect.placeholder", fallback: "We are here to help!") @@ -278,6 +344,16 @@ internal enum Localization { /// Thank you! internal static let message = Localization.tr("Localizable", "engagement.ended.message", fallback: "This engagement has ended.\nThank you!") } + internal enum MediaUpgrade { + internal enum Audio { + /// Speak through your device + internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.audio.info", fallback: "Speak through your device") + } + internal enum Phone { + /// Enter your number and we'll call you + internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.phone.info", fallback: "Enter your number and we'll call you") + } + } internal enum QueueClosed { /// We're sorry internal static let header = Localization.tr("Localizable", "engagement.queue_closed.header", fallback: "We're sorry") @@ -292,8 +368,8 @@ internal enum Localization { internal static let message = Localization.tr("Localizable", "engagement.queue_leave.message", fallback: "You will lose your place in the queue.") } internal enum QueueReconnectionFailed { - /// Please try again. - internal static let tryAgain = Localization.tr("Localizable", "engagement.queue_reconnection_failed.try_again", fallback: "Please try again.") + /// Please try again later. + internal static let tryAgain = Localization.tr("Localizable", "engagement.queue_reconnection_failed.try_again", fallback: "Please try again later.") } internal enum QueueTransferring { /// Transferring @@ -302,8 +378,6 @@ internal enum Localization { internal enum QueueWait { /// You can continue browsing and we will connect you automatically. internal static let message = Localization.tr("Localizable", "engagement.queue_wait.message", fallback: "You can continue browsing and we will connect you automatically.") - /// (By default your video will be off) - internal static let videoNotice = Localization.tr("Localizable", "engagement.queue_wait.video_notice", fallback: "(By default your video will be off)") } internal enum SecureMessaging { /// Messaging @@ -368,6 +442,28 @@ internal enum Localization { /// This action is not currently supported on mobile. internal static let errorUnsupported = Localization.tr("Localizable", "gva.error_unsupported", fallback: "This action is not currently supported on mobile.") } + internal enum Ios { + internal enum Engagement { + internal enum Alert { + internal enum Camera { + /// Allow access to your camera from device menu: “Settings” - “Privacy” - “Camera” + internal static let message = Localization.tr("Localizable", "ios.engagement.alert.camera.message", fallback: "Allow access to your camera from device menu: “Settings” - “Privacy” - “Camera”") + } + internal enum MediaSource { + /// This media source is not available on your device + internal static let message = Localization.tr("Localizable", "ios.engagement.alert.media_source.message", fallback: "This media source is not available on your device") + } + internal enum Microphone { + /// Allow access to your microphone from device menu: “Settings” - “Privacy” - “Microphone” + internal static let message = Localization.tr("Localizable", "ios.engagement.alert.microphone.message", fallback: "Allow access to your microphone from device menu: “Settings” - “Privacy” - “Microphone”") + } + } + internal enum QueueWait { + /// (By default your video will be off) + internal static let videoNotice = Localization.tr("Localizable", "ios.engagement.queue_wait.video_notice", fallback: "(By default your video will be off)") + } + } + } internal enum Media { internal enum Audio { /// Audio diff --git a/GliaWidgets/Resources/en.lproj/Localizable.strings b/GliaWidgets/Resources/en.lproj/Localizable.strings index ce2a4a555..dc002be71 100644 --- a/GliaWidgets/Resources/en.lproj/Localizable.strings +++ b/GliaWidgets/Resources/en.lproj/Localizable.strings @@ -81,7 +81,7 @@ "call.buttons.chat.badge_value.single_item.accessibility.label" = "{badgeValue} unread message"; "call.connect.first_text.accessibility.hint" = "Displays operator name."; "call.connect.second_text.accessibility.hint" = "Displays call duration."; -"call.header.close.button.accessibility.hint" = "Activates minimize."; +"call.header.back.button.accessibility.hint" = "Activates minimize."; "call.onHold.bottom_text" = "You can continue browsing while you are on hold"; "call.on_hold" = "On Hold"; "call.operator.avatar.accessibility.hint" = "Displays operator avatar or placeholder."; @@ -101,29 +101,38 @@ "call_visualizer.visitor_code.title.accessibility.hint" = "Your five-digit visitor code is"; "chat.duration.accessibility.label" = "Displays call duration."; "chat.attach_files" = "Pick attachment"; -"chat.attachement.photo_library" = "Photo Library"; -"chat.attachement.take_photo" = "Take Photo or Video"; -"chat.attachement.upload.unsupported_file" = "Invalid file type!"; +"chat.attachment.photo_library" = "Photo Library"; +"chat.attachment.take_photo" = "Take Photo or Video"; +"chat.attachment.upload.unsupported_file" = "Invalid file type!"; +"chat.attachment.message.accessibility.label" = "Attachment from {fileSender}"; "chat.download.downloading" = "Downloading file…"; +"chat.download.download" = "Download"; +"chat.download.failed" = "Download failed"; "chat.file.infected_error" = "Failed to confirm the safety of the file."; "chat.file.too_large_error" = "File size over 25MB limit!"; "chat.file.upload.failed" = "Uploading failed"; "chat.file.upload.in_progress" = "Uploading file…"; "chat.file.upload.scanning" = "Checking safety of the file…"; "chat.file.upload.success" = "Ready to send"; +"chat.file.upload.network_error" = "Network error."; +"chat.file.upload.generic_error" = "Network error."; "chat.input.placeholder" = "Enter Message"; "chat.input.send" = "Send"; "chat.message.unread.accessibility.label" = "Unread messages"; "chat.message.start_engagement_placeholder" = "Send a message to start chatting"; +"chat.message.choice_card_placeholder" = "Tap on the answer above"; "chat.operator.avatar.accessibility.label" = "Avatar"; "chat.operator.name.accessibility.label" = "Displays operator name."; "chat.operator_joined" = "{operatorName} has joined the conversation."; "chat.status.delivered" = "Delivered"; "chat.status.typing" = "Operator typing"; +"chat.status.typing.accessibility.label" = "{operatorName} is typing"; "chat.unread_message_divider" = "New Messages"; "chat.upgrade.audio.text" = "Upgraded to Audio Call"; "chat.upgrade.video.text" = "Upgraded to Video Call"; "chat.upload.remove.accessibility.label" = "Remove upload"; +"chat.choice_card.button.disabled.accessibility.label" = "Disabled"; +"chat.choice_card.image.accessibility.label" = "Choice card"; "engagement.connect.placeholder" = "We are here to help!"; "engagement.connect.with" = "Connecting with {operatorName}"; "engagement.default_operator_name" = "Operator"; @@ -131,15 +140,27 @@ "engagement.end.message" = "Are you sure you want to end engagement?"; "engagement.ended.header" = "Engagement Ended"; "engagement.ended.message" = "This engagement has ended.\nThank you!"; +"engagement.media_upgrade.audio.info" = "Speak through your device"; +"engagement.media_upgrade.phone.info" = "Enter your number and we'll call you"; +"engagement.alert.microphone.header" = "Unable to access microphone"; +"ios.engagement.alert.microphone.message" = "Allow access to your microphone from device menu: “Settings” - “Privacy” - “Microphone”"; +"engagement.alert.camera.header" = "Unable to access camera"; +"ios.engagement.alert.camera.message" = "Allow access to your camera from device menu: “Settings” - “Privacy” - “Camera”"; +"engagement.alert.media_source.header" = "Unable to access media source"; +"ios.engagement.alert.media_source.message" = "This media source is not available on your device"; +"engagement.alert.screen_sharing.start.header" = "{operatorName} has asked you to share your screen"; +"engagement.alert.screen_sharing.start.message" = "{operatorName} would like to see the screen of your device"; +"engagement.alert.screen_sharing.stop.header" = "Stop screen sharing?"; +"engagement.alert.screen_sharing.stop.message" = "Are you sure you want to stop sharing your screen?"; "engagement.minimize_video_button" = "Minimize"; "engagement.offer_upgrade" = "{operatorName} has offered you to upgrade"; "engagement.queue_closed.header" = "We're sorry"; "engagement.queue_closed.message" = "Operators are no longer available. \nPlease try again later."; "engagement.queue_leave.header" = "Are you sure you want to leave?"; "engagement.queue_leave.message" = "You will lose your place in the queue."; -"engagement.queue_reconnection_failed.try_again" = "Please try again."; +"engagement.queue_reconnection_failed.try_again" = "Please try again later."; "engagement.queue_transferring.message" = "Transferring"; -"engagement.queue_wait.video_notice" = "(By default your video will be off)"; +"ios.engagement.queue_wait.video_notice" = "(By default your video will be off)"; "engagement.queue_wait.message" = "You can continue browsing and we will connect you automatically."; "engagement.secure_messaging.title" = "Messaging"; "error.general" = "Something went wrong"; diff --git a/GliaWidgets/Sources/Theme/Survey/Theme.Survey.ValidationError.swift b/GliaWidgets/Sources/Theme/Survey/Theme.Survey.ValidationError.swift index 80d25e33c..977645e15 100644 --- a/GliaWidgets/Sources/Theme/Survey/Theme.Survey.ValidationError.swift +++ b/GliaWidgets/Sources/Theme/Survey/Theme.Survey.ValidationError.swift @@ -17,11 +17,11 @@ public extension Theme.SurveyStyle { font: ThemeFont ) -> Self { .init( - message: L10n.Survey.Action.validationError, + message: Localization.Survey.Action.validationError, color: color.systemNegative.hex, font: font.caption, accessibility: .init( - label: L10n.Survey.Accessibility.Validation.Title.label, + label: Localization.Survey.Validation.Title.Accessibility.label, isFontScalingEnabled: true ) ) diff --git a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift index cf970b5b7..83b110abb 100644 --- a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift +++ b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift @@ -1,45 +1,43 @@ extension Theme { var alertConfigurationStyle: AlertConfiguration { - typealias Alert = L10n.Alert - let leaveQueue = ConfirmationAlertConfiguration( - title: Alert.LeaveQueue.title, - message: Alert.LeaveQueue.message, - negativeTitle: Alert.Action.no, - positiveTitle: Alert.Action.yes, + title: Localization.Engagement.QueueLeave.header, + message: Localization.Engagement.QueueLeave.message, + negativeTitle: Localization.General.no, + positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, showsPoweredBy: false ) let endEngagement = ConfirmationAlertConfiguration( - title: Alert.EndEngagement.title, - message: Alert.EndEngagement.message, - negativeTitle: Alert.Action.no, - positiveTitle: Alert.Action.yes, + title: Localization.Engagement.End.Confirmation.header, + message: Localization.Engagement.End.message, + negativeTitle: Localization.General.no, + positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, showsPoweredBy: true ) let operatorEndedEngagement = SingleActionAlertConfiguration( - title: Alert.OperatorEndedEngagement.title, - message: Alert.OperatorEndedEngagement.message, - buttonTitle: Alert.Action.ok + title: Localization.Engagement.Ended.header, + message: Localization.Engagement.Ended.message, + buttonTitle: Localization.General.ok ) let endScreenShare = ConfirmationAlertConfiguration( - title: Alert.ScreenSharing.Stop.title, - message: Alert.ScreenSharing.Stop.message, - negativeTitle: Alert.Action.no, - positiveTitle: Alert.Action.yes, + title: Localization.Engagement.Alert.ScreenSharing.Stop.header, + message: Localization.Engagement.Alert.ScreenSharing.Stop.message, + negativeTitle: Localization.General.no, + positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, showsPoweredBy: showsPoweredBy ) let operatorsUnavailable = MessageAlertConfiguration( - title: Alert.OperatorsUnavailable.title, - message: Alert.OperatorsUnavailable.message + title: Localization.Engagement.QueueClosed.header, + message: Localization.Engagement.QueueClosed.message ) let audioAction = MediaUpgradeActionStyle( - title: Alert.MediaUpgrade.Audio.title, + title: Localization.Media.Audio.name, titleFont: font.header3, titleColor: color.baseDark, - info: Alert.MediaUpgrade.Audio.info, + info: Localization.Engagement.MediaUpgrade.Audio.info, infoFont: font.subtitle, infoColor: color.baseDark, borderColor: color.primary, @@ -48,10 +46,10 @@ extension Theme { iconColor: color.primary ) let phoneAction = MediaUpgradeActionStyle( - title: Alert.MediaUpgrade.Phone.title, + title: Localization.Media.Phone.name, titleFont: font.header3, titleColor: color.baseDark, - info: Alert.MediaUpgrade.Phone.info, + info: Localization.Engagement.MediaUpgrade.Phone.info, infoFont: font.subtitle, infoColor: color.baseDark, borderColor: color.primary, @@ -60,78 +58,78 @@ extension Theme { iconColor: color.primary ) let mediaUpgrade = MultipleMediaUpgradeAlertConfiguration( - title: Alert.MediaUpgrade.title, + title: Localization.Engagement.offerUpgrade, audioUpgradeAction: audioAction, phoneUpgradeAction: phoneAction, showsPoweredBy: showsPoweredBy ) let audioUpgrade = SingleMediaUpgradeAlertConfiguration( - title: Alert.AudioUpgrade.title, + title: Localization.Upgrade.Audio.title, titleImage: Asset.upgradeAudio.image, - decline: Alert.Action.decline, - accept: Alert.Action.accept, + decline: Localization.General.decline, + accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let oneWayVideoUpgrade = SingleMediaUpgradeAlertConfiguration( - title: Alert.VideoUpgrade.OneWay.title, + title: Localization.Upgrade.Video.OneWay.title, titleImage: Asset.upgradeVideo.image, - decline: Alert.Action.decline, - accept: Alert.Action.accept, + decline: Localization.General.decline, + accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let twoWayVideoUpgrade = SingleMediaUpgradeAlertConfiguration( - title: Alert.VideoUpgrade.TwoWay.title, + title: Localization.Upgrade.Video.TwoWay.title, titleImage: Asset.upgradeVideo.image, - decline: Alert.Action.decline, - accept: Alert.Action.accept, + decline: Localization.General.decline, + accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let screenShareOffer = ScreenShareOfferAlertConfiguration( - title: Alert.ScreenSharing.Start.title, - message: Alert.ScreenSharing.Start.message, + title: Localization.Engagement.Alert.ScreenSharing.Start.header, + message: Localization.Engagement.Alert.ScreenSharing.Start.message, titleImage: Asset.startScreenShare.image, - decline: Alert.Action.decline, - accept: Alert.Action.accept, + decline: Localization.General.decline, + accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let microphoneSettings = SettingsAlertConfiguration( - title: Alert.MicrophonePermission.title, - message: Alert.MicrophonePermission.message, - settingsTitle: Alert.Action.settings, - cancelTitle: Alert.Action.cancel + title: Localization.Engagement.Alert.Microphone.header, + message: Localization.Ios.Engagement.Alert.Microphone.message, + settingsTitle: Localization.Alert.Action.settings, + cancelTitle: Localization.General.cancel ) let cameraSettings = SettingsAlertConfiguration( - title: Alert.CameraPermission.title, - message: Alert.CameraPermission.message, - settingsTitle: Alert.Action.settings, - cancelTitle: Alert.Action.cancel + title: Localization.Engagement.Alert.Camera.header, + message: Localization.Ios.Engagement.Alert.Camera.message, + settingsTitle: Localization.Alert.Action.settings, + cancelTitle: Localization.General.cancel ) let mediaSourceNotAvailable = MessageAlertConfiguration( - title: Alert.MediaSourceNotAvailable.title, - message: Alert.MediaSourceNotAvailable.message + title: Localization.Engagement.Alert.MediaSource.header, + message: Localization.Ios.Engagement.Alert.MediaSource.message ) let unexpected = MessageAlertConfiguration( - title: Alert.Unexpected.title, - message: Alert.Unexpected.message + title: Localization.Error.Unexpected.title, + message: Localization.Engagement.QueueReconnectionFailed.tryAgain ) let api = MessageAlertConfiguration( - title: Alert.ApiError.title, - message: Alert.ApiError.message + title: Localization.Error.Unexpected.title, + message: L10n.Alert.ApiError.message ) let unavailableMessageCenter = MessageAlertConfiguration( - title: Alert.UnavailableMessageCenter.title, - message: Alert.UnavailableMessageCenter.message, + title: Localization.MessageCenter.Unavailable.title, + message: Localization.MessageCenter.Unavailable.message, shouldShowCloseButton: false ) let unavailableMessageCenterForBeingUnauthenticated = MessageAlertConfiguration( - title: Alert.UnavailableMessageCenter.title, - message: Alert.UnavailableMessageCenter.notAuthenticatedMessage, + title: Localization.MessageCenter.Unavailable.title, + message: Localization.MessageCenter.NotAuthenticated.message, shouldShowCloseButton: false ) let unsupportedGvaBroadcastError = MessageAlertConfiguration( - title: L10n.gvaNotSupported, + title: Localization.Gva.errorUnsupported, message: nil ) diff --git a/GliaWidgets/Sources/Theme/Theme+Call.swift b/GliaWidgets/Sources/Theme/Theme+Call.swift index 8c98aa55f..b4ff09d8d 100644 --- a/GliaWidgets/Sources/Theme/Theme+Call.swift +++ b/GliaWidgets/Sources/Theme/Theme+Call.swift @@ -12,7 +12,7 @@ extension Theme { color: color.baseLight, accessibility: .init( label: Localization.General.back, - hint: Localization.Call.Header.Close.Button.Accessibility.hint + hint: Localization.Call.Header.Back.Button.Accessibility.hint ) ) let closeButton = HeaderButtonStyle( @@ -165,7 +165,7 @@ extension Theme { operatorNameColor: color.baseLight, durationFont: font.bodyText, durationColor: color.baseLight, - topText: Localization.Engagement.QueueWait.videoNotice, + topText: Localization.Ios.Engagement.QueueWait.videoNotice, topTextFont: font.subtitle, topTextColor: color.baseLight, bottomText: Localization.Engagement.QueueWait.message, diff --git a/GliaWidgets/Sources/Theme/Theme+Chat.swift b/GliaWidgets/Sources/Theme/Theme+Chat.swift index 1b9ab6663..fa8f2016f 100644 --- a/GliaWidgets/Sources/Theme/Theme+Chat.swift +++ b/GliaWidgets/Sources/Theme/Theme+Chat.swift @@ -1,8 +1,5 @@ extension Theme { var chatStyle: ChatStyle { - typealias Chat = L10n.Chat - typealias Accessibility = Chat.Accessibility - let onHoldOverlay = OnHoldOverlayStyle( image: Asset.callOnHold.image, imageColor: .fill(color: .white), @@ -12,25 +9,25 @@ extension Theme { image: Asset.back.image, color: color.baseLight, accessibility: .init( - label: Accessibility.Header.BackButton.label, - hint: Accessibility.Header.BackButton.hint + label: Localization.General.back, + hint: "" ) ) let closeButton = HeaderButtonStyle( image: Asset.close.image, color: color.baseLight, accessibility: .init( - label: Accessibility.Header.CloseButton.label, - hint: Accessibility.Header.CloseButton.hint + label: Localization.General.close, + hint: "" ) ) let endButton = ActionButtonStyle( - title: Chat.EndButton.title, + title: Localization.General.end, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.systemNegative), accessibility: .init( - label: Accessibility.Header.EndButton.label, + label: Localization.General.end, isFontScalingEnabled: true ) ) @@ -38,8 +35,8 @@ extension Theme { image: Asset.startScreenShare.image, color: color.baseLight, accessibility: .init( - label: Accessibility.Header.EndScreenShareButton.label, - hint: Accessibility.Header.EndScreenShareButton.hint + label: Localization.ScreenSharing.VisitorScreen.end, + hint: "" ) ) let header = HeaderStyle( @@ -68,72 +65,72 @@ extension Theme { animationColor: color.primary, onHoldOverlay: onHoldOverlay, accessibility: .init( - label: Accessibility.Operator.Avatar.label, - hint: Accessibility.Operator.Avatar.hint + label: Localization.Chat.Operator.Avatar.Accessibility.label, + hint: Localization.Call.Operator.Avatar.Accessibility.hint ) ) let queue = ConnectStatusStyle( - firstText: Chat.Connect.Queue.firstText, + firstText: Localization.General.companyName, firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, - secondText: Chat.Connect.Queue.secondText, + secondText: Localization.Engagement.Connect.placeholder, secondTextFont: font.subtitle, secondTextFontColor: color.baseNormal, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Accessibility.Connect.Queue.FirstText.hint, + firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) ) let connecting = ConnectStatusStyle( - firstText: Chat.Connect.Connecting.firstText, + firstText: Localization.Engagement.Connect.with, firstTextFont: font.header2, firstTextFontColor: color.baseDark, firstTextStyle: .title2, - secondText: Chat.Connect.Connecting.secondText, + secondText: "", secondTextFont: font.header2, secondTextFontColor: color.baseDark, secondTextStyle: .title2, accessibility: .init( - firstTextHint: Accessibility.Connect.Connecting.FirstText.hint, + firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) ) let connected = ConnectStatusStyle( - firstText: Chat.Connect.Connected.firstText, + firstText: L10n.Chat.Connect.Connected.firstText, firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, - secondText: Chat.Connect.Connected.secondText, + secondText: Localization.Chat.operatorJoined, secondTextFont: font.subtitle, secondTextFontColor: color.primary, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Accessibility.Connect.Connected.FirstText.hint, + firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) ) let onHold = ConnectStatusStyle( - firstText: Chat.Connect.Connected.firstText, + firstText: L10n.Chat.Connect.Connected.firstText, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: Chat.Connect.Connected.secondText, + secondText: Localization.Chat.operatorJoined, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Accessibility.Connect.Connected.FirstText.hint, + firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) ) let transferring = ConnectStatusStyle( - firstText: Chat.Connect.Transferring.firstText, + firstText: Localization.Engagement.QueueTransferring.message, firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, @@ -153,8 +150,8 @@ extension Theme { let visitorImageFile = ChatImageFileContentStyle( backgroundColor: color.primary, accessibility: .init( - contentAccessibilityLabel: Accessibility.Message.attachmentMessageLabel, - youAccessibilityPlaceholder: Accessibility.Message.you, + contentAccessibilityLabel: Localization.Chat.Attachment.Message.Accessibility.label, + youAccessibilityPlaceholder: Localization.General.you, isFontScalingEnabled: true ) ) @@ -179,14 +176,14 @@ extension Theme { textStyle: .caption1, accessibility: .init(isFontScalingEnabled: true) ), - delivered: Chat.Message.Status.delivered, + delivered: Localization.Chat.Status.delivered, accessibility: .init(isFontScalingEnabled: true) ) let operatorImageFile = ChatImageFileContentStyle( backgroundColor: Color.lightGrey, accessibility: .init( - contentAccessibilityLabel: Accessibility.Message.attachmentMessageLabel, - youAccessibilityPlaceholder: Accessibility.Message.you, + contentAccessibilityLabel: Localization.Chat.Attachment.Message.Accessibility.label, + youAccessibilityPlaceholder: Localization.General.you, isFontScalingEnabled: true ) ) @@ -211,13 +208,13 @@ extension Theme { ) let operatorTypingIndicator = OperatorTypingIndicatorStyle( color: color.primary, - accessibility: .init(label: Accessibility.Message.Operator.TypingIndicator.label) + accessibility: .init(label: Localization.Chat.Status.Typing.Accessibility.label) ) let choiceCardImageFile = ChatImageFileContentStyle( backgroundColor: color.baseLight, accessibility: .init( - contentAccessibilityLabel: Accessibility.Message.attachmentMessageLabel, - youAccessibilityPlaceholder: Accessibility.Message.you, + contentAccessibilityLabel: Localization.Chat.Attachment.Message.Accessibility.label, + youAccessibilityPlaceholder: Localization.General.you, isFontScalingEnabled: true ) ) @@ -231,7 +228,7 @@ extension Theme { ), cornerRadius: 4, accessibility: .init( - label: Accessibility.Message.ChoiceCard.ButtonState.normal, + label: "", isFontScalingEnabled: true ) ) @@ -245,7 +242,7 @@ extension Theme { ), cornerRadius: 4, accessibility: .init( - label: Accessibility.Message.ChoiceCard.ButtonState.selected, + label: Localization.General.selected, isFontScalingEnabled: true ) ) @@ -261,7 +258,7 @@ extension Theme { borderWidth: 1, borderColor: Color.baseShade.toRGBAHex(), accessibility: .init( - label: Accessibility.Message.ChoiceCard.ButtonState.disabled, + label: Localization.Chat.ChoiceCard.Button.Disabled.Accessibility.label, isFontScalingEnabled: true ) ) @@ -287,24 +284,24 @@ extension Theme { fileDownload: fileDownload, operatorImage: operatorImage, choiceOption: choiceCardOption, - accessibility: .init(imageLabel: Accessibility.Message.ChoiceCard.Image.label) + accessibility: .init(imageLabel: Localization.Chat.ChoiceCard.Image.Accessibility.label) ) let mediaButton = MessageButtonStyle( image: Asset.chatPickMedia.image, color: color.baseNormal, - accessibility: .init(accessibilityLabel: Accessibility.PickMedia.PickAttachmentButton.label) + accessibility: .init(accessibilityLabel: Localization.Chat.attachFiles) ) let sendButton = MessageButtonStyle( image: Asset.chatSend.image, color: color.primary, - accessibility: .init(accessibilityLabel: Accessibility.Message.SendButton.label) + accessibility: .init(accessibilityLabel: Localization.Chat.Input.send) ) let messageEntry = ChatMessageEntryStyle( messageFont: font.bodyText, messageColor: color.baseDark, - enterMessagePlaceholder: Chat.Message.enterMessagePlaceholder, - startEngagementPlaceholder: Chat.Message.startEngagementPlaceholder, - choiceCardPlaceholder: Chat.Message.choiceCardPlaceholder, + enterMessagePlaceholder: Localization.Chat.Input.placeholder, + startEngagementPlaceholder: Localization.Chat.Message.startEngagementPlaceholder, + choiceCardPlaceholder: Localization.Chat.Message.choiceCardPlaceholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, separatorColor: color.baseShade, @@ -313,35 +310,35 @@ extension Theme { sendButton: sendButton, uploadList: uploadListStyle, accessibility: .init( - messageInputAccessibilityLabel: Accessibility.Message.MessageInput.label, + messageInputAccessibilityLabel: Localization.General.message, isFontScalingEnabled: true ) ) let audioUpgrade = ChatCallUpgradeStyle( icon: Asset.upgradeAudio.image, iconColor: color.primary, - text: Chat.Upgrade.Audio.text, + text: Localization.Chat.Upgrade.Audio.text, textFont: font.bodyText, textColor: color.baseDark, durationFont: font.bodyText, durationColor: color.baseNormal, borderColor: color.baseShade, accessibility: .init( - durationTextHint: Accessibility.ChatCallUpgrade.Audio.Duration.hint, + durationTextHint: Localization.Chat.Duration.Accessibility.label, isFontScalingEnabled: true ) ) let videoUpgrade = ChatCallUpgradeStyle( icon: Asset.upgradeVideo.image, iconColor: color.primary, - text: Chat.Upgrade.Video.text, + text: Localization.Chat.Upgrade.Video.text, textFont: font.bodyText, textColor: color.baseDark, durationFont: font.bodyText, durationColor: color.baseNormal, borderColor: color.baseShade, accessibility: .init( - durationTextHint: Accessibility.ChatCallUpgrade.Video.Duration.hint, + durationTextHint: Localization.Chat.Duration.Accessibility.label, isFontScalingEnabled: true ) ) @@ -355,8 +352,8 @@ extension Theme { let callBubble = BubbleStyle( userImage: userImage, accessibility: .init( - label: L10n.Call.Accessibility.Bubble.label, - hint: L10n.Call.Accessibility.Bubble.hint + label: Localization.Call.Operator.Avatar.Accessibility.label, + hint: Localization.Call.Bubble.Accessibility.hint ) ) let unreadMessageIndicator = UnreadMessageIndicatorStyle( @@ -368,11 +365,11 @@ extension Theme { placeholderBackgroundColor: .fill(color: color.primary), imageBackgroundColor: .fill(color: .clear), transferringImage: Asset.operatorTransferring.image, - accessibility: .init(label: Accessibility.Message.UnreadMessagesIndicator.label) + accessibility: .init(label: Localization.Chat.Message.Unread.Accessibility.label) ) let unreadMessageDivider = UnreadMessageDividerStyle( - title: Chat.SecureTranscript.unreadMessageDividerTitle, + title: Localization.Chat.unreadMessageDivider, titleColor: Color.baseNormal, titleFont: font.buttonLabel, lineColor: Color.primary, @@ -396,7 +393,7 @@ extension Theme { connect: connect, backgroundColor: .fill(color: color.background), preferredStatusBarStyle: .lightContent, - title: Chat.title, + title: Localization.Media.Text.name, visitorMessageStyle: visitorMessage, operatorMessageStyle: operatorMessage, choiceCardStyle: choiceCard, @@ -408,11 +405,11 @@ extension Theme { unreadMessageIndicator: unreadMessageIndicator, operatorTypingIndicator: operatorTypingIndicator, accessibility: .init( - operator: L10n.operator, - visitor: Accessibility.visitorName, + operator: Localization.Engagement.defaultOperatorName, + visitor: Localization.General.you, isFontScalingEnabled: true ), - secureTranscriptTitle: Chat.SecureTranscript.headerTitle, + secureTranscriptTitle: Localization.Engagement.SecureMessaging.title, secureTranscriptHeader: secureTranscriptHeader, unreadMessageDivider: unreadMessageDivider, systemMessageStyle: systemMessage, @@ -421,9 +418,6 @@ extension Theme { } private var uploadListStyle: FileUploadListStyle { - typealias Upload = L10n.Chat.Upload - typealias Accessibility = L10n.Chat.Accessibility.Upload - let filePreview = FilePreviewStyle( fileFont: font.subtitle, fileColor: color.baseLight, @@ -434,30 +428,30 @@ extension Theme { accessibility: .init(isFontScalingEnabled: true) ) let uploading = FileUploadStateStyle( - text: Upload.uploading, + text: Localization.Chat.File.Upload.inProgress, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let uploaded = FileUploadStateStyle( - text: Upload.uploaded, + text: Localization.Chat.File.Upload.success, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let error = FileUploadErrorStateStyle( - text: Upload.failed, + text: Localization.Chat.File.Upload.failed, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.systemNegative, - infoFileTooBig: Upload.Error.fileTooBig, - infoUnsupportedFileType: Upload.Error.unsupportedFileType, - infoSafetyCheckFailed: Upload.Error.safetyCheckFailed, - infoNetworkError: Upload.Error.network, - infoGenericError: Upload.Error.generic + infoFileTooBig: Localization.Chat.File.tooLargeError, + infoUnsupportedFileType: Localization.Chat.Attachment.Upload.unsupportedFile, + infoSafetyCheckFailed: Localization.Chat.File.infectedError, + infoNetworkError: Localization.Chat.File.Upload.networkError, + infoGenericError: Localization.Chat.File.Upload.genericError ) let upload = FileUploadStyle( filePreview: filePreview, @@ -470,9 +464,9 @@ extension Theme { removeButtonImage: Asset.uploadRemove.image, removeButtonColor: color.baseNormal, accessibility: .init( - removeButtonAccessibilityLabel: Accessibility.RemoveUpload.label, - progressPercentValue: Accessibility.Progress.percentValue, - fileNameWithProgressValue: Accessibility.Progress.fileNameWithProgressValue, + removeButtonAccessibilityLabel: Localization.Chat.Upload.Remove.Accessibility.label, + progressPercentValue: L10n.Chat.Accessibility.Upload.Progress.percentValue, + fileNameWithProgressValue: L10n.Chat.Accessibility.Upload.Progress.fileNameWithProgressValue, isFontScalingEnabled: true ) ) @@ -481,9 +475,6 @@ extension Theme { } private var fileDownload: ChatFileDownloadStyle { - typealias Download = L10n.Chat.Download - typealias Accessibility = L10n.Chat.Accessibility - let filePreview = FilePreviewStyle( fileFont: font.subtitle, fileColor: color.baseLight, @@ -494,36 +485,36 @@ extension Theme { accessibility: .init(isFontScalingEnabled: true) ) let download = ChatFileDownloadStateStyle( - text: Download.download, + text: Localization.Chat.Download.download, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let downloading = ChatFileDownloadStateStyle( - text: Download.downloading, + text: Localization.Chat.Download.downloading, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let open = ChatFileDownloadStateStyle( - text: Download.open, + text: Localization.General.open, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let error = ChatFileDownloadErrorStateStyle( - text: Download.failed, + text: Localization.Chat.Download.failed, font: font.mediumSubtitle2, textColor: color.systemNegative, infoFont: font.caption, infoColor: color.baseNormal, - separatorText: Download.Failed.separator, + separatorText: " | ", separatorFont: font.subtitle, separatorTextColor: color.baseDark, - retryText: Download.Failed.retry, + retryText: Localization.General.retry, retryFont: font.mediumSubtitle2, retryTextColor: color.baseDark ) @@ -540,29 +531,27 @@ extension Theme { backgroundColor: .white, borderColor: Color.lightGrey, accessibility: .init( - contentAccessibilityLabel: Accessibility.Message.attachmentMessageLabel, - youAccessibilityPlaceholder: Accessibility.Message.you, + contentAccessibilityLabel: Localization.Chat.Attachment.Message.Accessibility.label, + youAccessibilityPlaceholder: Localization.General.you, isFontScalingEnabled: true ), downloadAccessibility: .init( - noneState: Accessibility.Download.State.none, - downloadingState: Accessibility.Download.State.downloading, - downloadedState: Accessibility.Download.State.downloaded, - errorState: Accessibility.Download.State.error + noneState: L10n.Chat.Accessibility.Download.State.none, + downloadingState: L10n.Chat.Accessibility.Download.State.downloading, + downloadedState: L10n.Chat.Accessibility.Download.State.downloaded, + errorState: L10n.Chat.Accessibility.Download.State.error ) ) } private var pickMedia: AttachmentSourceListStyle { - typealias Chat = L10n.Chat.PickMedia - let itemFont = font.bodyText let itemFontColor = color.baseDark let itemIconColor = color.baseDark let pickPhoto = AttachmentSourceItemStyle( kind: .photoLibrary, - title: Chat.photo, + title: Localization.Chat.Attachment.photoLibrary, titleFont: itemFont, titleColor: itemFontColor, icon: Asset.photoLibraryIcon.image, @@ -571,7 +560,7 @@ extension Theme { ) let takePhoto = AttachmentSourceItemStyle( kind: .takePhoto, - title: Chat.takePhoto, + title: Localization.Chat.Attachment.takePhoto, titleFont: itemFont, titleColor: itemFontColor, icon: Asset.cameraIcon.image, @@ -580,7 +569,7 @@ extension Theme { ) let browse = AttachmentSourceItemStyle( kind: .browse, - title: Chat.browse, + title: Localization.General.browse, titleFont: itemFont, titleColor: itemFontColor, icon: Asset.browseIcon.image, diff --git a/GliaWidgets/Sources/Theme/Theme+MinimizedBubble.swift b/GliaWidgets/Sources/Theme/Theme+MinimizedBubble.swift index 816d77d4b..2a00933ad 100644 --- a/GliaWidgets/Sources/Theme/Theme+MinimizedBubble.swift +++ b/GliaWidgets/Sources/Theme/Theme+MinimizedBubble.swift @@ -22,8 +22,8 @@ extension Theme { badge: badge, onHoldOverlay: onHoldOverlay, accessibility: .init( - label: L10n.Call.Accessibility.Bubble.label, - hint: L10n.Call.Accessibility.Bubble.hint + label: Localization.Call.Bubble.Accessibility.label, + hint: Localization.Call.Bubble.Accessibility.hint ) ) } From 357fee68141d9f97260c0a30f20e6baf781afe47 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Mon, 28 Aug 2023 12:17:52 +0300 Subject: [PATCH 15/40] Replace old strings in remaining views All remaining strings that have a direct translation in the new Localization enum are now removed. The only strings remaining are the ones that need a translation layer, because they use variables. MOB-2538 --- GliaWidgets/Localization.swift | 4 +- .../Resources/en.lproj/Localizable.strings | 2 +- ...heme+SecureConversationsConfirmation.swift | 14 ++--- .../Theme+SecureConversationsWelcome.swift | 61 ++++++++----------- .../ViewModel/VideoCallViewModel.swift | 4 +- .../VisitorCode/VisitorCodeView.swift | 16 ++--- .../Sources/Theme/Survey/Theme+Survey.swift | 6 +- .../Sources/Theme/Theme+ScreenSharing.swift | 8 +-- .../Sources/Theme/Theme+VisitorCode.swift | 4 +- 9 files changed, 54 insertions(+), 65 deletions(-) diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index 8def76126..ae8e858d5 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -213,8 +213,8 @@ internal enum Localization { internal enum Upload { /// Uploading failed internal static let failed = Localization.tr("Localizable", "chat.file.upload.failed", fallback: "Uploading failed") - /// Network error. - internal static let genericError = Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Network error.") + /// Failed to upload. + internal static let genericError = Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Failed to upload.") /// Uploading file… internal static let inProgress = Localization.tr("Localizable", "chat.file.upload.in_progress", fallback: "Uploading file…") /// Network error. diff --git a/GliaWidgets/Resources/en.lproj/Localizable.strings b/GliaWidgets/Resources/en.lproj/Localizable.strings index dc002be71..af2ef409e 100644 --- a/GliaWidgets/Resources/en.lproj/Localizable.strings +++ b/GliaWidgets/Resources/en.lproj/Localizable.strings @@ -115,7 +115,7 @@ "chat.file.upload.scanning" = "Checking safety of the file…"; "chat.file.upload.success" = "Ready to send"; "chat.file.upload.network_error" = "Network error."; -"chat.file.upload.generic_error" = "Network error."; +"chat.file.upload.generic_error" = "Failed to upload."; "chat.input.placeholder" = "Enter Message"; "chat.input.send" = "Send"; "chat.message.unread.accessibility.label" = "Unread messages"; diff --git a/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift b/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift index b40c4f48b..bb02f5b08 100644 --- a/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift +++ b/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift @@ -4,41 +4,39 @@ extension Theme { /// Default style for confirmation screen in secure conversation. Be aware it depends on /// `self.colors` (ThemeColor). var defaultSecureConversationsConfirmationStyle: SecureConversations.ConfirmationStyle { - typealias Confirmation = L10n.MessageCenter.Confirmation - let chatStyle = chatStyle var header = chatStyle.header header.backButton = nil let titleStyle = SecureConversations.ConfirmationStyle.TitleStyle( - text: Confirmation.title, + text: Localization.General.thankYou, font: font.header1, color: color.baseDark, accessibility: .init(isFontScalingEnabled: true) ) let subtitleStyle = SecureConversations.ConfirmationStyle.SubtitleStyle( - text: Confirmation.subtitle, + text: Localization.MessageCenter.Confirmation.subtitle, font: font.bodyText, color: color.baseDark, accessibility: .init(isFontScalingEnabled: true) ) let checkMessagesButtonStyle = SecureConversations.ConfirmationStyle.CheckMessagesButtonStyle( - title: Confirmation.checkMessages, + title: Localization.MessageCenter.checkMessages, font: font.bodyText, textColor: color.baseLight, backgroundColor: color.primary, accessibility: .init( isFontScalingEnabled: true, - label: Confirmation.Accessibility.checkMessagesLabel, - hint: Confirmation.Accessibility.checkMessagesHint + label: Localization.MessageCenter.Confirmation.CheckMessages.Accessibility.label, + hint: Localization.MessageCenter.Confirmation.CheckMessages.Accessibility.hint ) ) return .init( header: header, - headerTitle: Confirmation.header, + headerTitle: Localization.MessageCenter.header, confirmationImage: Asset.mcEnvelope.image, confirmationImageTint: color.primary, titleStyle: titleStyle, diff --git a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift index 7b852ee38..f2a5cafb0 100644 --- a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift +++ b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift @@ -9,7 +9,7 @@ extension Theme { header.backButton = nil let welcomeTitleStyle = SecureConversations.WelcomeStyle.TitleStyle( - text: Welcome.title, + text: Localization.MessageCenter.Welcome.title, font: font.header3, textStyle: .title3, color: .black, @@ -17,7 +17,7 @@ extension Theme { ) let welcomeSubtitleStyle = SecureConversations.WelcomeStyle.SubtitleStyle( - text: Welcome.subtitle, + text: Localization.MessageCenter.Welcome.subtitle, font: font.subtitle, textStyle: .footnote, color: .black, @@ -32,12 +32,12 @@ extension Theme { accessibility: .init( isFontScalingEnabled: true, label: Localization.MessageCenter.checkMessages, - hint: Welcome.CheckMessages.Accessibility.hint + hint: Localization.MessageCenter.Welcome.CheckMessages.Accessibility.hint ) ) let messageTitleStyle = SecureConversations.WelcomeStyle.MessageTitleStyle( - title: Welcome.messageTitle, + title: Localization.MessageCenter.Welcome.messageTitle, font: font.mediumSubtitle1, textStyle: .subheadline, color: .black, @@ -45,7 +45,7 @@ extension Theme { ) let messageTextViewNormalStyle = SecureConversations.WelcomeStyle.MessageTextViewNormalStyle( - placeholderText: Welcome.MessageTextView.placeholder, + placeholderText: Localization.MessageCenter.Welcome.MessageTextView.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -59,7 +59,7 @@ extension Theme { ) let messageTextViewActiveStyle = SecureConversations.WelcomeStyle.MessageTextViewActiveStyle( - placeholderText: Welcome.MessageTextView.placeholder, + placeholderText: Localization.MessageCenter.Welcome.MessageTextView.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -73,7 +73,7 @@ extension Theme { ) let messageTextViewDisabledStyle = SecureConversations.WelcomeStyle.MessageTextViewDisabledStyle( - placeholderText: Welcome.MessageTextView.placeholder, + placeholderText: Localization.MessageCenter.Welcome.MessageTextView.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -104,7 +104,7 @@ extension Theme { accessibility: .init( isFontScalingEnabled: true, label: Localization.Chat.Input.send, - hint: Welcome.Send.Accessibility.hint + hint: Localization.MessageCenter.Welcome.Send.Accessibility.hint ) ) @@ -120,7 +120,7 @@ extension Theme { accessibility: .init( isFontScalingEnabled: true, label: Localization.Chat.Input.send, - hint: Welcome.Send.Accessibility.hint + hint: Localization.MessageCenter.Welcome.Send.Accessibility.hint ) ) @@ -137,7 +137,7 @@ extension Theme { accessibility: .init( isFontScalingEnabled: true, label: Localization.Chat.Input.send, - hint: Welcome.Send.Accessibility.hint + hint: Localization.MessageCenter.Welcome.Send.Accessibility.hint ) ) @@ -152,7 +152,7 @@ extension Theme { textFont: .systemFont(ofSize: 12.0), textStyle: .caption1, iconColor: color.systemNegative, - messageLengthLimitText: L10n.MessageCenter.Welcome.messageLengthWarning, + messageLengthLimitText: Localization.MessageCenter.Welcome.messageLengthWarning, accessibility: .init(isFontScalingEnabled: true) ) @@ -161,8 +161,8 @@ extension Theme { disabledColor: .lightGray, accessibility: .init( isFontScalingEnabled: true, - accessibilityLabel: Welcome.FilePicker.Accessibility.label, - accessibilityHint: Welcome.FilePicker.Accessibility.hint + accessibilityLabel: Localization.MessageCenter.Welcome.FilePicker.Accessibility.label, + accessibilityHint: Localization.MessageCenter.Welcome.FilePicker.Accessibility.hint ) ) @@ -172,11 +172,6 @@ extension Theme { ) var uploadListStyle: MessageCenterFileUploadListStyle { - // TODO: Introduce dedicated localization for Secure conversations upload list instaed of using Chat's one. - // MOB-1831 - typealias Upload = L10n.Chat.Upload - typealias Accessibility = L10n.Chat.Accessibility.Upload - let filePreview = FilePreviewStyle( fileFont: font.subtitle, fileColor: color.baseLight, @@ -187,30 +182,30 @@ extension Theme { accessibility: .init(isFontScalingEnabled: true) ) let uploading = FileUploadStateStyle( - text: Upload.uploading, + text: Localization.Chat.File.Upload.inProgress, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let uploaded = FileUploadStateStyle( - text: Upload.uploaded, + text: Localization.Chat.File.Upload.success, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.baseNormal ) let error = FileUploadErrorStateStyle( - text: Upload.failed, + text: Localization.Chat.File.Upload.failed, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, infoColor: color.systemNegative, - infoFileTooBig: Upload.Error.fileTooBig, - infoUnsupportedFileType: Upload.Error.unsupportedFileType, - infoSafetyCheckFailed: Upload.Error.safetyCheckFailed, - infoNetworkError: Upload.Error.network, - infoGenericError: Upload.Error.generic + infoFileTooBig: Localization.Chat.File.tooLargeError, + infoUnsupportedFileType: Localization.Chat.Attachment.Upload.unsupportedFile, + infoSafetyCheckFailed: Localization.Chat.File.infectedError, + infoNetworkError: Localization.Chat.File.Upload.networkError, + infoGenericError: Localization.Chat.File.Upload.genericError ) let upload = MessageCenterFileUploadStyle( filePreview: filePreview, @@ -224,9 +219,9 @@ extension Theme { removeButtonColor: color.baseNormal, backgroundColor: .commonGray, accessibility: .init( - removeButtonAccessibilityLabel: Accessibility.RemoveUpload.label, - progressPercentValue: Accessibility.Progress.percentValue, - fileNameWithProgressValue: Accessibility.Progress.fileNameWithProgressValue, + removeButtonAccessibilityLabel: Localization.Chat.Upload.Remove.Accessibility.label, + progressPercentValue: L10n.Chat.Accessibility.Upload.Progress.percentValue, + fileNameWithProgressValue: L10n.Chat.Accessibility.Upload.Progress.fileNameWithProgressValue, isFontScalingEnabled: true ) ) @@ -237,15 +232,13 @@ extension Theme { // TODO: Introduce dedicated localization for Secure conversations upload list instaed of using Chat's one. // MOB-1831 var pickMediaStyle: AttachmentSourceListStyle { - typealias Chat = L10n.Chat.PickMedia - let itemFont = font.bodyText let itemFontColor = color.baseDark let itemIconColor = color.baseDark let pickPhoto = AttachmentSourceItemStyle( kind: .photoLibrary, - title: Chat.photo, + title: Localization.Chat.Attachment.photoLibrary, titleFont: itemFont, titleColor: itemFontColor, icon: Asset.photoLibraryIcon.image, @@ -254,7 +247,7 @@ extension Theme { ) let takePhoto = AttachmentSourceItemStyle( kind: .takePhoto, - title: Chat.takePhoto, + title: Localization.Chat.Attachment.takePhoto, titleFont: itemFont, titleColor: itemFontColor, icon: Asset.cameraIcon.image, @@ -263,7 +256,7 @@ extension Theme { ) let browse = AttachmentSourceItemStyle( kind: .browse, - title: Chat.browse, + title: Localization.General.browse, titleFont: itemFont, titleColor: itemFontColor, icon: Asset.browseIcon.image, diff --git a/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift b/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift index 71b423348..2ad5b7f61 100644 --- a/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift +++ b/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift @@ -101,7 +101,7 @@ extension CallVisualizer { videoButtonState = .active videoButtonEnabled = true minimizeButtonEnabled = true - title = L10n.Call.Video.title + title = Localization.Media.Video.name callDuration = "" topLabelHidden = false endScreenShareButtonHidden = environment.screenShareHandler.status().value == .stopped @@ -505,7 +505,7 @@ private extension CallVisualizer.VideoCallViewModel { default: topLabelHidden = true } - title = L10n.Call.Video.title + title = Localization.Media.Video.name } updateButtons() } diff --git a/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift b/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift index 1002aa83c..3c166e4e5 100644 --- a/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift +++ b/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift @@ -75,8 +75,8 @@ extension CallVisualizer { let refreshButton = UIButton().make { button in button.accessibilityIdentifier = "visitor_code_refresh_button" button.accessibilityTraits = .button - button.accessibilityLabel = L10n.CallVisualizer.VisitorCode.Accessibility.refreshLabel - button.accessibilityHint = L10n.CallVisualizer.VisitorCode.Accessibility.refreshHint + button.accessibilityLabel = Localization.CallVisualizer.VisitorCode.Refresh.Accessibility.label + button.accessibilityHint = Localization.CallVisualizer.VisitorCode.Refresh.Accessibility.hint } let spinnerView = UIImageView().make { imageView in imageView.image = Asset.spinner.image.withRenderingMode(.alwaysTemplate) @@ -102,8 +102,8 @@ extension CallVisualizer { ).make { button in button.accessibilityIdentifier = "visitor_code_alert_close_button" button.accessibilityTraits = .button - button.accessibilityLabel = L10n.CallVisualizer.VisitorCode.Accessibility.closeLabel - button.accessibilityHint = L10n.CallVisualizer.VisitorCode.Accessibility.closeHint + button.accessibilityLabel = Localization.CallVisualizer.VisitorCode.Close.Accessibility.label + button.accessibilityHint = Localization.CallVisualizer.VisitorCode.Close.Accessibility.hint } lazy var poweredBy: PoweredBy = PoweredBy(style: props.style.poweredBy) @@ -266,15 +266,15 @@ extension CallVisualizer.VisitorCodeView { switch props.viewState { case .success(visitorCode: let code): renderedVisitorCode = code - titleLabel.text = L10n.CallVisualizer.VisitorCode.Title.standard + titleLabel.text = Localization.CallVisualizer.VisitorCode.title renderVisitorCode() - titleLabel.accessibilityHint = L10n.CallVisualizer.VisitorCode.Accessibility.titleHint + titleLabel.accessibilityHint = Localization.CallVisualizer.VisitorCode.Title.Accessibility.hint case .error: - titleLabel.text = L10n.CallVisualizer.VisitorCode.Title.error + titleLabel.text = Localization.VisitorCode.failed renderError() titleLabel.accessibilityHint = nil case .loading: - titleLabel.text = L10n.CallVisualizer.VisitorCode.Title.standard + titleLabel.text = Localization.CallVisualizer.VisitorCode.title renderSpinner() } setFontScalingEnabled( diff --git a/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift b/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift index 03b8ec48b..563428bf5 100644 --- a/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift +++ b/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift @@ -2,7 +2,6 @@ import Foundation import UIKit extension Theme { - public struct SurveyStyle { /// Layer style. public var layer: Layer @@ -53,7 +52,6 @@ extension Theme.SurveyStyle { font: ThemeFont, alertStyle: AlertStyle ) -> Self { - let font = ThemeFontStyle.default.font return .init( @@ -71,14 +69,14 @@ extension Theme.SurveyStyle { submitButton: .init( actionButtonStyle: alertStyle.positiveAction, accessibility: .init( - label: L10n.Survey.Accessibility.Footer.SubmitButton.label, + label: Localization.General.submit, isFontScalingEnabled: true ) ), cancellButton: .init( actionButtonStyle: alertStyle.negativeAction, accessibility: .init( - label: L10n.Survey.Accessibility.Footer.CancelButton.label, + label: Localization.General.cancel, isFontScalingEnabled: true ) ), diff --git a/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift b/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift index b0867ed12..f84e90f4d 100644 --- a/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift +++ b/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift @@ -3,19 +3,19 @@ import UIKit extension Theme { var screenSharingStyle: ScreenSharingViewStyle { return ScreenSharingViewStyle( - title: L10n.CallVisualizer.ScreenSharing.title, + title: Localization.CallVisualizer.ScreenSharing.title, header: chat.header, - messageText: L10n.CallVisualizer.ScreenSharing.message, + messageText: Localization.CallVisualizer.ScreenSharing.message, messageTextFont: font.header2, messageTextColor: color.baseDark, buttonStyle: .init( - title: L10n.CallVisualizer.ScreenSharing.Button.title, + title: Localization.ScreenSharing.VisitorScreen.end, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.systemNegative), cornerRaidus: 4, accessibility: .init( - label: L10n.CallVisualizer.ScreenSharing.Button.title, + label: Localization.ScreenSharing.VisitorScreen.end, isFontScalingEnabled: true ) ), diff --git a/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift b/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift index 3fa7cd594..11d3f6667 100644 --- a/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift +++ b/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift @@ -13,14 +13,14 @@ extension Theme { ) let actionButton = ActionButtonStyle( - title: L10n.CallVisualizer.VisitorCode.Action.refresh, + title: Localization.CallVisualizer.VisitorCode.Action.refresh, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.primary) ) let poweredBy = PoweredByStyle( - text: L10n.poweredBy, + text: Localization.General.poweredBy, font: font.caption, accessibility: .init(isFontScalingEnabled: true) ) From 26f5ef3728c6c4d14acae0f688c0ff4861e3d48d Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Fri, 1 Sep 2023 16:28:35 +0300 Subject: [PATCH 16/40] Update strings that don't need a translation layer There was a small amount of strings that I incorrectly identified as needing additional work to change, but it was just a matter of replacing because they are all internal and not exposed to the integrators. MOB-2507 --- .../VideoCall/ViewModel/VideoCallViewModel.swift | 4 +--- .../Components/ButtonView/Survey.ButtonView.swift | 6 ++++-- GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift | 10 ++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift b/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift index 2ad5b7f61..a1962baf4 100644 --- a/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift +++ b/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift @@ -487,9 +487,7 @@ private extension CallVisualizer.VideoCallViewModel { private extension CallVisualizer.VideoCallViewModel { func onDurationChanged(_ duration: Int) { - let text = L10n.Call.Connect.Connected.secondText.withCallDuration( - duration.asDurationString - ) + let text = duration.asDurationString callDuration = text } diff --git a/GliaWidgets/Sources/ViewController/Survey/Components/ButtonView/Survey.ButtonView.swift b/GliaWidgets/Sources/ViewController/Survey/Components/ButtonView/Survey.ButtonView.swift index c439b6e45..edaedb075 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Components/ButtonView/Survey.ButtonView.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Components/ButtonView/Survey.ButtonView.swift @@ -16,9 +16,11 @@ extension Survey { var label: String { switch state { case .selected: - return L10n.Survey.Accessibility.Question.OptionButton.Selected.label.withButtonTitle(title) + return Localization.Survey.Question.OptionButton.Selected.Accessibility.label + .withButtonTitle(title) case .active, .highlighted: - return L10n.Survey.Accessibility.Question.OptionButton.Unselected.label.withButtonTitle(title) + return Localization.Survey.Question.OptionButton.Unselected.Accessibility.label + .withButtonTitle(title) } } return .init(label: label) diff --git a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift index a742d4c8e..9076368fd 100644 --- a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift @@ -93,11 +93,7 @@ class CallViewModel: EngagementViewModel, ViewModel { action?(.queue) case .engaged: showConnecting() - - let operatorName = L10n.Call.Operator.name.withOperatorName( - interactor.engagedOperator?.firstName - ) - + let operatorName = interactor.engagedOperator?.firstName ?? Localization.Engagement.defaultOperatorName action?(.setOperatorName(operatorName)) case .ended: call.end() @@ -389,9 +385,7 @@ extension CallViewModel { } private func onDurationChanged(_ duration: Int) { - let text = L10n.Call.Connect.Connected.secondText.withCallDuration( - duration.asDurationString - ) + let text = duration.asDurationString action?(.setCallDurationText(text)) } } From 97909f9512a2897ec016541037e79410c916d134 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Mon, 4 Sep 2023 14:46:50 +0300 Subject: [PATCH 17/40] Internalize templated strings Instead of creating a layer that verifies if a string has a template or not, the templates (for example, `{operatorImage}`) have been captured in an internal extension of the `Localization` struct. That way integrators have a deprecation that they shouldn't use our strings anymore in case they do, but also the minimum amount of changes is done to the workings on the SDK. So we can still use templated strings as right now without going and changing a bunch of SDK functionality. MOB-2507 --- GliaWidgets.xcodeproj/project.pbxproj | 4 ++++ GliaWidgets/Localization+Templates.swift | 14 +++++++++++++ .../Theme+SecureConversationsWelcome.swift | 4 ++-- .../Theme/Theme+AlertConfiguration.swift | 2 +- GliaWidgets/Sources/Theme/Theme+Call.swift | 20 +++++++++---------- GliaWidgets/Sources/Theme/Theme+Chat.swift | 16 +++++++-------- .../CheckboxView/Survey.Checkbox.swift | 6 ++++-- .../CallVisualizer/VisitorCodeTests.swift | 6 +++--- 8 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 GliaWidgets/Localization+Templates.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 8662c0858..00d5a5640 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -186,6 +186,7 @@ 315BAB1A29ADFEBC00FF284B /* ConfirmationStyle+TitleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BAB1929ADFEBC00FF284B /* ConfirmationStyle+TitleStyle.swift */; }; 315BAB1C29ADFEC800FF284B /* ConfirmationStyle+SubtitleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BAB1B29ADFEC800FF284B /* ConfirmationStyle+SubtitleStyle.swift */; }; 315BAB1E29ADFED800FF284B /* ConfirmationStyle+CheckMessagesButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BAB1D29ADFED800FF284B /* ConfirmationStyle+CheckMessagesButtonStyle.swift */; }; + 31882C9B2AA21B71009DE4BD /* Localization+Templates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31882C9A2AA21B71009DE4BD /* Localization+Templates.swift */; }; 3189DD9429DEFAC600D68E9F /* SecureConversations.WelcomeViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3189DD9329DEFAC600D68E9F /* SecureConversations.WelcomeViewModelSpec.swift */; }; 3189DD9629E4331200D68E9F /* SecureConversations.WelcomeViewModel.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3189DD9529E4331200D68E9F /* SecureConversations.WelcomeViewModel.Mock.swift */; }; 3197F7AD29E6A5C8008EE9F7 /* SecureConversations.FileUploadListView.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3197F7AC29E6A5C8008EE9F7 /* SecureConversations.FileUploadListView.Mock.swift */; }; @@ -926,6 +927,7 @@ 315BAB1929ADFEBC00FF284B /* ConfirmationStyle+TitleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfirmationStyle+TitleStyle.swift"; sourceTree = ""; }; 315BAB1B29ADFEC800FF284B /* ConfirmationStyle+SubtitleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfirmationStyle+SubtitleStyle.swift"; sourceTree = ""; }; 315BAB1D29ADFED800FF284B /* ConfirmationStyle+CheckMessagesButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfirmationStyle+CheckMessagesButtonStyle.swift"; sourceTree = ""; }; + 31882C9A2AA21B71009DE4BD /* Localization+Templates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Localization+Templates.swift"; sourceTree = ""; }; 3189DD9329DEFAC600D68E9F /* SecureConversations.WelcomeViewModelSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewModelSpec.swift; sourceTree = ""; }; 3189DD9529E4331200D68E9F /* SecureConversations.WelcomeViewModel.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.WelcomeViewModel.Mock.swift; sourceTree = ""; }; 3197F7AC29E6A5C8008EE9F7 /* SecureConversations.FileUploadListView.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.FileUploadListView.Mock.swift; sourceTree = ""; }; @@ -1674,6 +1676,7 @@ 1A205D5C25655CB1003AA3CD /* Info.plist */, 1A60AFAE256680EF00E53F53 /* L10n.swift */, 31E35AB92A8648E9006EC7FB /* Localization.swift */, + 31882C9A2AA21B71009DE4BD /* Localization+Templates.swift */, 31DB0C00287C2EFC00FB288E /* StaticValues.swift */, ); path = GliaWidgets; @@ -4583,6 +4586,7 @@ 7594093E298D376B008B173A /* RemoteConfiguration.swift in Sources */, 1AC7A7AF258786CB00567FF8 /* EngagementViewModel.swift in Sources */, 9AE9E4B327E0E60F00BFE239 /* CallViewModel.Mock.swift in Sources */, + 31882C9B2AA21B71009DE4BD /* Localization+Templates.swift in Sources */, 845876A8282A94CF007AC3DF /* BooleanQuestionView.Props.Accessibility.swift in Sources */, 1A6EBB2525ADE36900EE325D /* MediaUpgradePresenter.swift in Sources */, 1AA738B925790DB400E1120F /* ActionButtonStyle.swift in Sources */, diff --git a/GliaWidgets/Localization+Templates.swift b/GliaWidgets/Localization+Templates.swift new file mode 100644 index 000000000..b011d413e --- /dev/null +++ b/GliaWidgets/Localization+Templates.swift @@ -0,0 +1,14 @@ +import Foundation + +extension Localization { + enum Templates { + static let percentValue = "{uploadPercentValue}%" + static let fileNameWithProgressValue = "{uploadedFileName}, {uploadPercentValue}%" + static let operatorName = "{operatorName}" + static let callDuration = "{callDuration}" + static let titleAndBadgeValue = "{buttonTitle}, {badgeValue}" + static let errorMessage = "{message}" + static let downloadWithFileState = "{downloadedFileName}, {downloadedFileState}" + static let downloadWithFileStateAndPercentValue = "{downloadedFileName}, {downloadedFileState} {downloadPercentValue}%" + } +} diff --git a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift index f2a5cafb0..8ae9f92ab 100644 --- a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift +++ b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift @@ -220,8 +220,8 @@ extension Theme { backgroundColor: .commonGray, accessibility: .init( removeButtonAccessibilityLabel: Localization.Chat.Upload.Remove.Accessibility.label, - progressPercentValue: L10n.Chat.Accessibility.Upload.Progress.percentValue, - fileNameWithProgressValue: L10n.Chat.Accessibility.Upload.Progress.fileNameWithProgressValue, + progressPercentValue: Localization.Templates.percentValue, + fileNameWithProgressValue: Localization.Templates.fileNameWithProgressValue, isFontScalingEnabled: true ) ) diff --git a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift index 83b110abb..55249e3ae 100644 --- a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift +++ b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift @@ -114,7 +114,7 @@ extension Theme { ) let api = MessageAlertConfiguration( title: Localization.Error.Unexpected.title, - message: L10n.Alert.ApiError.message + message: Localization.Templates.errorMessage ) let unavailableMessageCenter = MessageAlertConfiguration( title: Localization.MessageCenter.Unavailable.title, diff --git a/GliaWidgets/Sources/Theme/Theme+Call.swift b/GliaWidgets/Sources/Theme/Theme+Call.swift index b4ff09d8d..df7d96c9b 100644 --- a/GliaWidgets/Sources/Theme/Theme+Call.swift +++ b/GliaWidgets/Sources/Theme/Theme+Call.swift @@ -98,11 +98,11 @@ extension Theme { ) ) let connected = ConnectStatusStyle( - firstText: L10n.Call.Connect.Connected.firstText, + firstText: Localization.Templates.operatorName, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: L10n.Call.Connect.Connected.secondText, + secondText: Localization.Templates.callDuration, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, @@ -113,11 +113,11 @@ extension Theme { ) ) let onHold = ConnectStatusStyle( - firstText: L10n.Call.Connect.Connected.firstText, + firstText: Localization.Templates.operatorName, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: L10n.Call.Connect.Connected.secondText, + secondText: Localization.Templates.callDuration, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, @@ -160,7 +160,7 @@ extension Theme { preferredStatusBarStyle: .lightContent, audioTitle: Localization.Media.Audio.name, videoTitle: Localization.Media.Video.name, - operatorName: L10n.Call.Operator.name, + operatorName: Localization.Templates.operatorName, operatorNameFont: font.header1, operatorNameColor: color.baseLight, durationFont: font.bodyText, @@ -229,7 +229,7 @@ extension Theme { accessibility: .init( singleItemBadgeValue: Localization.Call.Buttons.Chat.BadgeValue.SingleItem.Accessibility.label, multipleItemsBadgeValue: Localization.Call.Buttons.Chat.BadgeValue.MultipleItems.Accessibility.label, - titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Chat.titleAndBadgeValue, + titleAndBadgeValue: Localization.Templates.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -269,7 +269,7 @@ extension Theme { accessibility: .init( singleItemBadgeValue: "", multipleItemsBadgeValue: "", - titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Video.titleAndBadgeValue, + titleAndBadgeValue: Localization.Templates.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -309,7 +309,7 @@ extension Theme { accessibility: .init( singleItemBadgeValue: "", multipleItemsBadgeValue: "", - titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Mute.titleAndBadgeValue, + titleAndBadgeValue: Localization.Templates.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -349,7 +349,7 @@ extension Theme { accessibility: .init( singleItemBadgeValue: "", multipleItemsBadgeValue: "", - titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Speaker.titleAndBadgeValue, + titleAndBadgeValue: Localization.Templates.titleAndBadgeValue, isFontScalingEnabled: true ) ) @@ -389,7 +389,7 @@ extension Theme { accessibility: .init( singleItemBadgeValue: "", multipleItemsBadgeValue: "", - titleAndBadgeValue: L10n.Call.Accessibility.Buttons.Minimize.titleAndBadgeValue, + titleAndBadgeValue: Localization.Templates.titleAndBadgeValue, isFontScalingEnabled: true ) ) diff --git a/GliaWidgets/Sources/Theme/Theme+Chat.swift b/GliaWidgets/Sources/Theme/Theme+Chat.swift index fa8f2016f..89592c4be 100644 --- a/GliaWidgets/Sources/Theme/Theme+Chat.swift +++ b/GliaWidgets/Sources/Theme/Theme+Chat.swift @@ -100,7 +100,7 @@ extension Theme { ) ) let connected = ConnectStatusStyle( - firstText: L10n.Chat.Connect.Connected.firstText, + firstText: Localization.Templates.operatorName, firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, @@ -115,7 +115,7 @@ extension Theme { ) ) let onHold = ConnectStatusStyle( - firstText: L10n.Chat.Connect.Connected.firstText, + firstText: Localization.Templates.operatorName, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, @@ -465,8 +465,8 @@ extension Theme { removeButtonColor: color.baseNormal, accessibility: .init( removeButtonAccessibilityLabel: Localization.Chat.Upload.Remove.Accessibility.label, - progressPercentValue: L10n.Chat.Accessibility.Upload.Progress.percentValue, - fileNameWithProgressValue: L10n.Chat.Accessibility.Upload.Progress.fileNameWithProgressValue, + progressPercentValue: Localization.Templates.percentValue, + fileNameWithProgressValue: Localization.Templates.fileNameWithProgressValue, isFontScalingEnabled: true ) ) @@ -536,10 +536,10 @@ extension Theme { isFontScalingEnabled: true ), downloadAccessibility: .init( - noneState: L10n.Chat.Accessibility.Download.State.none, - downloadingState: L10n.Chat.Accessibility.Download.State.downloading, - downloadedState: L10n.Chat.Accessibility.Download.State.downloaded, - errorState: L10n.Chat.Accessibility.Download.State.error + noneState: Localization.Templates.downloadWithFileState, + downloadingState: Localization.Templates.downloadWithFileStateAndPercentValue, + downloadedState: Localization.Templates.downloadWithFileState, + errorState: Localization.Templates.downloadWithFileState ) ) } diff --git a/GliaWidgets/Sources/ViewController/Survey/Components/CheckboxView/Survey.Checkbox.swift b/GliaWidgets/Sources/ViewController/Survey/Components/CheckboxView/Survey.Checkbox.swift index c33a5fb04..9ea8f0614 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Components/CheckboxView/Survey.Checkbox.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Components/CheckboxView/Survey.Checkbox.swift @@ -16,9 +16,11 @@ extension Survey { var label: String { switch state { case .selected: - return L10n.Survey.Accessibility.Question.OptionButton.Selected.label.withButtonTitle(title) + return Localization.Survey.Question.OptionButton.Selected.Accessibility.label + .withButtonTitle(title) case .active, .highlighted: - return L10n.Survey.Accessibility.Question.OptionButton.Unselected.label.withButtonTitle(title) + return Localization.Survey.Question.OptionButton.Unselected.Accessibility.label + .withButtonTitle(title) } } return .init(label: label) diff --git a/GliaWidgetsTests/CallVisualizer/VisitorCodeTests.swift b/GliaWidgetsTests/CallVisualizer/VisitorCodeTests.swift index 201650983..d4433cee8 100644 --- a/GliaWidgetsTests/CallVisualizer/VisitorCodeTests.swift +++ b/GliaWidgetsTests/CallVisualizer/VisitorCodeTests.swift @@ -19,21 +19,21 @@ class VisitorCodeTests: XCTestCase { let view = CallVisualizer.VisitorCodeView() view.props = .init(viewState: .success(visitorCode: visitorCode)) XCTAssertEqual(visitorCode, view.renderedVisitorCode, "Visitor Code not displayed properly") - XCTAssertEqual(view.titleLabel.text, L10n.CallVisualizer.VisitorCode.Title.standard) + XCTAssertEqual(view.titleLabel.text, Localization.CallVisualizer.VisitorCode.title) } func test_error_displayed() { let view = CallVisualizer.VisitorCodeView() view.props = .init(viewState: .error(refreshTap: .nop)) XCTAssertTrue(view.stackView.arrangedSubviews.contains(view.refreshButton)) - XCTAssertEqual(view.titleLabel.text, L10n.CallVisualizer.VisitorCode.Title.error) + XCTAssertEqual(view.titleLabel.text, Localization.VisitorCode.failed) } func test_spinner_displayed() { let view = CallVisualizer.VisitorCodeView() view.props = .init(viewState: .loading) XCTAssertTrue(view.stackView.arrangedSubviews.contains(view.spinnerView)) - XCTAssertEqual(view.titleLabel.text, L10n.CallVisualizer.VisitorCode.Title.standard) + XCTAssertEqual(view.titleLabel.text, Localization.CallVisualizer.VisitorCode.title) } func test_closeButton_visibility() { From b9b6bcc5fa35d41609dd2b0ffbeff5dad69e60e3 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Wed, 13 Sep 2023 11:05:12 +0300 Subject: [PATCH 18/40] Introduce string providing mechanism The proposal is that the Core SDK will return to us a dictionary with the keys and values just as they come from the backend. This is also exactly how the strings are saved in the `Localizable.strings` file, accessed through the `Localization` enum. When the Core SDK is configured and is able to provide the dictionary, we save it to a StringProviding struct. When a string is accessed through the use of `Localization`, then `Localization` knows what is the key of the string, and also specifies a fallback in case reading from the file fails. So with this same key, we can go to the StringProviding, consult the dictionary, and if the string is not there, use the file fallback, and if not use the string fallback. This means that with this simple PR, once the Core SDK provides the dictionary, we support custom locales for the whole Widgets SDK with minimal effort. The alternative is to create a model which we need to keep in sync between Core and Widgets, which seems like a big mess. MOB-2282 --- GliaWidgets.xcodeproj/project.pbxproj | 20 ++++++ .../Localization+StringProviding.swift | 22 +++++++ GliaWidgets/Localization.swift | 21 ------ GliaWidgets/Public/Glia/Glia.swift | 14 ++-- GliaWidgets/StringProviding.swift | 5 ++ .../Resources/LocalizationTests.swift | 66 +++++++++++++++++++ swiftgen-strings.stencil | 27 -------- 7 files changed, 123 insertions(+), 52 deletions(-) create mode 100644 GliaWidgets/Localization+StringProviding.swift create mode 100644 GliaWidgets/StringProviding.swift create mode 100644 GliaWidgetsTests/Resources/LocalizationTests.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 00d5a5640..f9510c532 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -183,6 +183,8 @@ 311CAFCD29F8FAE20067B59F /* SecureConversations.TranscriptModel+CustomCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311CAFCC29F8FAE20067B59F /* SecureConversations.TranscriptModel+CustomCard.swift */; }; 313EBD552943116E008E9597 /* SecureConversations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 313EBD542943116E008E9597 /* SecureConversations.swift */; }; 3142696A29FFB712003DF62E /* Interactor.Failing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3142696929FFB712003DF62E /* Interactor.Failing.swift */; }; + 3146C9432AB1851C0047D8CC /* LocalizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3146C9422AB1851C0047D8CC /* LocalizationTests.swift */; }; + 3146C9492AB18AC70047D8CC /* Localization+StringProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3146C9482AB18AC70047D8CC /* Localization+StringProviding.swift */; }; 315BAB1A29ADFEBC00FF284B /* ConfirmationStyle+TitleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BAB1929ADFEBC00FF284B /* ConfirmationStyle+TitleStyle.swift */; }; 315BAB1C29ADFEC800FF284B /* ConfirmationStyle+SubtitleStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BAB1B29ADFEC800FF284B /* ConfirmationStyle+SubtitleStyle.swift */; }; 315BAB1E29ADFED800FF284B /* ConfirmationStyle+CheckMessagesButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 315BAB1D29ADFED800FF284B /* ConfirmationStyle+CheckMessagesButtonStyle.swift */; }; @@ -195,6 +197,7 @@ 3197F7B429F7C26A008EE9F7 /* SecureConversations.ChatWithTranscriptViewModel+Hashable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3197F7B329F7C26A008EE9F7 /* SecureConversations.ChatWithTranscriptViewModel+Hashable.swift */; }; 3197F7B629F7C2E5008EE9F7 /* SecureConversations.SecureChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3197F7B529F7C2E5008EE9F7 /* SecureConversations.SecureChatModel.swift */; }; 3197F7B829F7C318008EE9F7 /* SecureConversations.CommonEngagementModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3197F7B729F7C318008EE9F7 /* SecureConversations.CommonEngagementModel.swift */; }; + 31B1F8A92AB093ED009EC5AD /* StringProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31B1F8A82AB093ED009EC5AD /* StringProviding.swift */; }; 31D286AD2A00DD2C009192A6 /* SecureConversations.ConfirmationViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D286AC2A00DD2C009192A6 /* SecureConversations.ConfirmationViewModelTests.swift */; }; 31D286AF2A00DE2B009192A6 /* SecureConversations.ConfirmationViewModel.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31D286AE2A00DE2B009192A6 /* SecureConversations.ConfirmationViewModel.Mock.swift */; }; 31DB0C01287C2EFC00FB288E /* StaticValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31DB0C00287C2EFC00FB288E /* StaticValues.swift */; }; @@ -924,6 +927,8 @@ 311CAFCC29F8FAE20067B59F /* SecureConversations.TranscriptModel+CustomCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SecureConversations.TranscriptModel+CustomCard.swift"; sourceTree = ""; }; 313EBD542943116E008E9597 /* SecureConversations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.swift; sourceTree = ""; }; 3142696929FFB712003DF62E /* Interactor.Failing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Interactor.Failing.swift; sourceTree = ""; }; + 3146C9422AB1851C0047D8CC /* LocalizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationTests.swift; sourceTree = ""; }; + 3146C9482AB18AC70047D8CC /* Localization+StringProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Localization+StringProviding.swift"; sourceTree = ""; }; 315BAB1929ADFEBC00FF284B /* ConfirmationStyle+TitleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfirmationStyle+TitleStyle.swift"; sourceTree = ""; }; 315BAB1B29ADFEC800FF284B /* ConfirmationStyle+SubtitleStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfirmationStyle+SubtitleStyle.swift"; sourceTree = ""; }; 315BAB1D29ADFED800FF284B /* ConfirmationStyle+CheckMessagesButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConfirmationStyle+CheckMessagesButtonStyle.swift"; sourceTree = ""; }; @@ -936,6 +941,7 @@ 3197F7B329F7C26A008EE9F7 /* SecureConversations.ChatWithTranscriptViewModel+Hashable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SecureConversations.ChatWithTranscriptViewModel+Hashable.swift"; sourceTree = ""; }; 3197F7B529F7C2E5008EE9F7 /* SecureConversations.SecureChatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.SecureChatModel.swift; sourceTree = ""; }; 3197F7B729F7C318008EE9F7 /* SecureConversations.CommonEngagementModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.CommonEngagementModel.swift; sourceTree = ""; }; + 31B1F8A82AB093ED009EC5AD /* StringProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringProviding.swift; sourceTree = ""; }; 31D286AC2A00DD2C009192A6 /* SecureConversations.ConfirmationViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.ConfirmationViewModelTests.swift; sourceTree = ""; }; 31D286AE2A00DE2B009192A6 /* SecureConversations.ConfirmationViewModel.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureConversations.ConfirmationViewModel.Mock.swift; sourceTree = ""; }; 31DB0C00287C2EFC00FB288E /* StaticValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StaticValues.swift; sourceTree = ""; }; @@ -1676,7 +1682,9 @@ 1A205D5C25655CB1003AA3CD /* Info.plist */, 1A60AFAE256680EF00E53F53 /* L10n.swift */, 31E35AB92A8648E9006EC7FB /* Localization.swift */, + 3146C9482AB18AC70047D8CC /* Localization+StringProviding.swift */, 31882C9A2AA21B71009DE4BD /* Localization+Templates.swift */, + 31B1F8A82AB093ED009EC5AD /* StringProviding.swift */, 31DB0C00287C2EFC00FB288E /* StaticValues.swift */, ); path = GliaWidgets; @@ -1685,6 +1693,7 @@ 1A205D6525655CB2003AA3CD /* GliaWidgetsTests */ = { isa = PBXGroup; children = ( + 3146C9412AB1850A0047D8CC /* Resources */, 7552DFB22A6FBC6E0093519B /* CoreSdk */, 7552DFAF2A6FB37E0093519B /* ChatMessage */, 846A5C3729D18D220049B29F /* ScreenShareHandler */, @@ -2588,6 +2597,14 @@ path = ChatTranscript; sourceTree = ""; }; + 3146C9412AB1850A0047D8CC /* Resources */ = { + isa = PBXGroup; + children = ( + 3146C9422AB1851C0047D8CC /* LocalizationTests.swift */, + ); + path = Resources; + sourceTree = ""; + }; 315BAB1829ADFE9E00FF284B /* ConfirmationStyle */ = { isa = PBXGroup; children = ( @@ -4383,6 +4400,7 @@ 846A5C4029ED83C50049B29F /* CallVisualizer.Coordinator.DelegateEvent.swift in Sources */, 845876B4282AA296007AC3DF /* ButtonView.Props.Accessibility.swift in Sources */, 1A0C9AE025C9624500815406 /* ObservableValue.swift in Sources */, + 31B1F8A92AB093ED009EC5AD /* StringProviding.swift in Sources */, 75940962298D3889008B173A /* MessageMetadata.swift in Sources */, 7594094D298D37E8008B173A /* Glia.Environment.Mock.swift in Sources */, 1A60AFB9256682AF00E53F53 /* FlowCoordinator.swift in Sources */, @@ -4654,6 +4672,7 @@ 3100EEF2293E214B00D57F71 /* SecureConversations.Coordinator.swift in Sources */, 1AA738AE2578E0D500E1120F /* ConnectAnimationView.swift in Sources */, 754CC61627E2816F005676E9 /* Survey.InputQuestionView.swift in Sources */, + 3146C9492AB18AC70047D8CC /* Localization+StringProviding.swift in Sources */, 9A1992DF27D62C2E00161AAE /* ImageView.Cache.Mock.swift in Sources */, 8491AF0D2A7A9CB900CC3E72 /* Theme.VisitorChatMessageStyle.swift in Sources */, 1A2DA72D25EF9DD900032611 /* FileUpload.swift in Sources */, @@ -4887,6 +4906,7 @@ 84681A952A61844000DD7406 /* ChatViewModelTests+Gva.swift in Sources */, 847A7643285A1914004044D1 /* FileUploadListViewModelTests.swift in Sources */, 9A1992E727D66C7400161AAE /* UIKitBased.Failing.swift in Sources */, + 3146C9432AB1851C0047D8CC /* LocalizationTests.swift in Sources */, 846A5C3929D18D400049B29F /* ScreenShareHandlerTests.swift in Sources */, 9AE05CB62805D2CB00871321 /* Interactor.Environment.Failing.swift in Sources */, 846429862A45DB4100943BD6 /* AlertViewController.Kind+Mock.swift in Sources */, diff --git a/GliaWidgets/Localization+StringProviding.swift b/GliaWidgets/Localization+StringProviding.swift new file mode 100644 index 000000000..0e79e20c3 --- /dev/null +++ b/GliaWidgets/Localization+StringProviding.swift @@ -0,0 +1,22 @@ +import Foundation + +extension Localization { + static func tr( + _ table: String, + _ key: String, + _ args: CVarArg..., + fallback value: String, + stringProviding: StringProviding? = Glia.sharedInstance.stringProviding, + bundleManaging: BundleManaging = .live + ) -> String { + guard + let stringProviding, + let remoteString = stringProviding.getRemoteString(key) + else { + let format = bundleManaging.current().localizedString(forKey: key, value: value, table: table) + return String(format: format, locale: Locale.current, arguments: args) + } + + return remoteString + } +} diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index ae8e858d5..995ab6b96 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -640,25 +640,4 @@ internal enum Localization { // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces -// MARK: - Implementation Details - -extension Localization { - private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { - let format = BundleToken.bundle.localizedString(forKey: key, value: value, table: table) - return String(format: format, locale: Locale.current, arguments: args) - } -} - -// swiftlint:disable convenience_type -private final class BundleToken { - static let bundle: Bundle = { - #if SWIFT_PACKAGE - return Bundle.module - #else - return Bundle(for: BundleToken.self) - #endif - }() -} -// swiftlint:enable convenience_type - // swiftlint:enable all diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index 84f2168bf..856a3eb82 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -57,6 +57,8 @@ public class Glia { /// Used to monitor engagement state changes. public var onEvent: ((GliaEvent) -> Void)? + var stringProviding: StringProviding? + public lazy var callVisualizer = CallVisualizer( environment: .init( data: environment.data, @@ -126,10 +128,14 @@ public class Glia { if let callback = completion { createdInteractor.withConfiguration { [weak createdInteractor] in guard let interactor = createdInteractor else { return } - interactor.state = GliaCore.sharedInstance - .getCurrentEngagement()?.engagedOperator - .map(InteractorState.engaged) ?? interactor.state - callback() + + // TODO: Configure string providing from Core SDK here. + + interactor.state = GliaCore.sharedInstance + .getCurrentEngagement()?.engagedOperator + .map(InteractorState.engaged) ?? interactor.state + + callback() } } diff --git a/GliaWidgets/StringProviding.swift b/GliaWidgets/StringProviding.swift new file mode 100644 index 000000000..cf21cda81 --- /dev/null +++ b/GliaWidgets/StringProviding.swift @@ -0,0 +1,5 @@ +import Foundation + +struct StringProviding { + var getRemoteString: ((String) -> String?) +} diff --git a/GliaWidgetsTests/Resources/LocalizationTests.swift b/GliaWidgetsTests/Resources/LocalizationTests.swift new file mode 100644 index 000000000..14a08f0c2 --- /dev/null +++ b/GliaWidgetsTests/Resources/LocalizationTests.swift @@ -0,0 +1,66 @@ +import Foundation +import XCTest +@testable import GliaWidgets + +final class LocalizationTests: XCTestCase { + let testString = "Glia" + + func test_stringProvider() { + let stringProviding = StringProviding(getRemoteString: { _ in self.testString }) + + let localizationString = Localization.tr( + "", + "", + fallback: "", + stringProviding: stringProviding + ) + + XCTAssertEqual(localizationString, testString) + } + + func test_fallback() { + let localizationString = Localization.tr( + "", + "", + fallback: testString + ) + + XCTAssertEqual(localizationString, testString) + } + + func test_fallbackWhenStringProvidingReturnsNil() { + let stringProviding = StringProviding(getRemoteString: { _ in nil }) + + let localizationString = Localization.tr( + "", + "", + fallback: testString, + stringProviding: stringProviding + ) + + XCTAssertEqual(localizationString, testString) + } + + func test_fileFromString() { + let localizationString = Localization.tr( + "Localizable", + "alert.action.settings", + fallback: "" + ) + + XCTAssertEqual(localizationString, "Settings") + } + + func test_fileFromStringWhenStringProvidingReturnsNil() { + let stringProviding = StringProviding(getRemoteString: { _ in nil }) + + let localizationString = Localization.tr( + "Localizable", + "alert.action.settings", + fallback: "", + stringProviding: stringProviding + ) + + XCTAssertEqual(localizationString, "Settings") + } +} diff --git a/swiftgen-strings.stencil b/swiftgen-strings.stencil index 62c97052d..3a56d2857 100644 --- a/swiftgen-strings.stencil +++ b/swiftgen-strings.stencil @@ -79,33 +79,6 @@ import Foundation } // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces - -// MARK: - Implementation Details - -extension {{enumName}} { - private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { - {% if param.lookupFunction %} - let format = {{ param.lookupFunction }}(key, table, value) - {% else %} - let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: value, table: table) - {% endif %} - return String(format: format, locale: Locale.current, arguments: args) - } -} -{% if not param.bundle and not param.lookupFunction %} - -// swiftlint:disable convenience_type -private final class BundleToken { - static let bundle: Bundle = { - #if SWIFT_PACKAGE - return Bundle.module - #else - return Bundle(for: BundleToken.self) - #endif - }() -} -// swiftlint:enable convenience_type -{% endif %} {% else %} // No string found {% endif %} From 38c2961d4983fc34ff0b36bf9cf71a06c3b57299 Mon Sep 17 00:00:00 2001 From: Egor Egorov Date: Thu, 21 Sep 2023 16:10:02 +0300 Subject: [PATCH 19/40] StringProviding integration StringProviding is set when configuration is done. Then this StringProviding will be used to retrieve remote string if exists, otherwise localized value is taken from local file. --- GliaWidgets/Public/Glia/Glia.Deprecated.swift | 15 +++++++++------ GliaWidgets/Public/Glia/Glia.swift | 12 ++++++------ .../CoreSDKClient/CoreSDKClient.Interface.swift | 8 ++++++++ .../CoreSDKClient/CoreSDKClient.Live.swift | 1 + .../CoreSDKClient/CoreSDKClient.Mock.swift | 5 +++++ GliaWidgetsTests/CoreSDKClient.Failing.swift | 12 +++++++++++- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/GliaWidgets/Public/Glia/Glia.Deprecated.swift b/GliaWidgets/Public/Glia/Glia.Deprecated.swift index b8f1b39de..96e8c7dd4 100644 --- a/GliaWidgets/Public/Glia/Glia.Deprecated.swift +++ b/GliaWidgets/Public/Glia/Glia.Deprecated.swift @@ -114,12 +114,15 @@ extension Glia { interactor = createdInteractor if let callback = completion { - createdInteractor.withConfiguration { [weak createdInteractor] in - guard let interactor = createdInteractor else { return } - interactor.state = GliaCore.sharedInstance - .getCurrentEngagement()?.engagedOperator - .map(InteractorState.engaged) ?? interactor.state - callback() + createdInteractor.withConfiguration { [weak createdInteractor, weak self] in + guard let createdInteractor, let self else { return } + + self.stringProviding = .init(getRemoteString: self.environment.coreSdk.localeProvider.getRemoteString) + + createdInteractor.state = self.environment.coreSdk + .getCurrentEngagement()?.engagedOperator + .map(InteractorState.engaged) ?? createdInteractor.state + callback() } } diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index 856a3eb82..5fbf3c006 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -126,14 +126,14 @@ public class Glia { interactor = createdInteractor if let callback = completion { - createdInteractor.withConfiguration { [weak createdInteractor] in - guard let interactor = createdInteractor else { return } + createdInteractor.withConfiguration { [weak createdInteractor, weak self] in + guard let createdInteractor, let self else { return } - // TODO: Configure string providing from Core SDK here. + self.stringProviding = .init(getRemoteString: self.environment.coreSdk.localeProvider.getRemoteString) - interactor.state = GliaCore.sharedInstance + createdInteractor.state = self.environment.coreSdk .getCurrentEngagement()?.engagedOperator - .map(InteractorState.engaged) ?? interactor.state + .map(InteractorState.engaged) ?? createdInteractor.state callback() } @@ -149,7 +149,7 @@ public class Glia { rootCoordinator?.minimize() } - /// Maximizes engagement view if ongoing engagment exists. + /// Maximizes engagement view if ongoing engagement exists. /// Throws error if ongoing engagement not exist. /// Use this function for resuming engagement view If bubble is hidden programmatically and you need to /// present engagement view. diff --git a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift index 945b82bd2..cb14acb1c 100644 --- a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift +++ b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift @@ -6,6 +6,7 @@ struct CoreSdkClient { var pushNotifications: PushNotifications var createAppDelegate: () -> AppDelegate var clearSession: () -> Void + var localeProvider: LocaleProvider typealias FetchVisitorInfo = (_ completion: @escaping (Result) -> Void) -> Void var fetchVisitorInfo: FetchVisitorInfo @@ -171,6 +172,13 @@ extension CoreSdkClient { } } +extension CoreSdkClient { + struct LocaleProvider { + typealias CustomLocaleGetRemoteString = ((String) -> String?) + var getRemoteString: CustomLocaleGetRemoteString + } +} + extension CoreSdkClient { typealias AnswerBlock = GliaCoreSDK.AnswerBlock typealias AnswerWithSuccessBlock = GliaCoreSDK.AnswerWithSuccessBlock diff --git a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Live.swift b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Live.swift index 7da29d155..c4823553a 100644 --- a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Live.swift +++ b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Live.swift @@ -6,6 +6,7 @@ extension CoreSdkClient { pushNotifications: .live, createAppDelegate: Self.AppDelegate.live, clearSession: GliaCore.sharedInstance.clearSession, + localeProvider: .init(getRemoteString: GliaCore.sharedInstance.localeProvider.getRemoteString(_:)), fetchVisitorInfo: GliaCore.sharedInstance.fetchVisitorInfo(_:), updateVisitorInfo: GliaCore.sharedInstance.updateVisitorInfo(_:completion:), configureWithConfiguration: GliaCore.sharedInstance.configure(with:completion:), diff --git a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Mock.swift b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Mock.swift index c091895b0..f73d91be2 100644 --- a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Mock.swift +++ b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Mock.swift @@ -7,6 +7,7 @@ extension CoreSdkClient { pushNotifications: .mock, createAppDelegate: { .mock }, clearSession: {}, + localeProvider: .mock, fetchVisitorInfo: { _ in }, updateVisitorInfo: { _, _ in }, configureWithConfiguration: { _, _ in }, @@ -53,6 +54,10 @@ extension CoreSdkClient.AppDelegate { ) } +extension CoreSdkClient.LocaleProvider { + static let mock = Self(getRemoteString: { _ in nil }) +} + extension CoreSdkClient.EngagementFile { static func mock(id: String = "") -> CoreSdkClient.EngagementFile { .init(id: id) diff --git a/GliaWidgetsTests/CoreSDKClient.Failing.swift b/GliaWidgetsTests/CoreSDKClient.Failing.swift index 9b2c7a6f8..b8f342fa4 100644 --- a/GliaWidgetsTests/CoreSDKClient.Failing.swift +++ b/GliaWidgetsTests/CoreSDKClient.Failing.swift @@ -5,11 +5,12 @@ extension CoreSdkClient { pushNotifications: .failing, createAppDelegate: { .failing }, clearSession: { fail("\(Self.self).clearSession") }, + localeProvider: .failing, fetchVisitorInfo: { _ in fail("\(Self.self).fetchVisitorInfo") }, updateVisitorInfo: { _, _ in fail("\(Self.self).updateVisitorInfo") }, configureWithConfiguration: { _, _ in fail("\(Self.self).configureWithConfiguration") }, configureWithInteractor: { _ in fail("\(Self.self).configureWithInteractor") }, - listQueues: {_ in fail("\(Self.self).listQueues") }, + listQueues: { _ in fail("\(Self.self).listQueues") }, queueForEngagement: { _, _ in fail("\(Self.self).queueForEngagement") }, requestMediaUpgradeWithOffer: { _, _ in fail("\(Self.self).requestMediaUpgradeWithOffer") }, sendMessagePreview: { _, _ in fail("\(Self.self).sendMessagePreview") }, @@ -89,3 +90,12 @@ extension CoreSdkClient.AppDelegate { } ) } + +extension CoreSdkClient.LocaleProvider { + static let failing = Self( + getRemoteString: { _ in + fail("\(Self.self).getRemoteString") + return nil + } + ) +} From f07b367558ab5d14ef65898f433cf645192c1e42 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Fri, 22 Sep 2023 16:56:05 +0300 Subject: [PATCH 20/40] Get company name from custom locales In this commit, support for adding a company name from custom locales is added. However, if the integrator has set this name through the theme, that one is used instead of the custom locales. Also, in case the custom locale doesn't have a string for the company name, but the integrator has specified a company name through the configuration of the SDK, then that is used. Finally, if neither of the previous possibilies have been used, then the local fallbacks are used. Together, the first and the last point mean that there are no backwards compatibility issues, as if the integrator hasn't set any name, still the local fallback will be displayed, which is "CompanyName". If they have, then that is used immediately without caring about configuration or custom locales. MOB-2686 --- GliaWidgets.xcodeproj/project.pbxproj | 8 -- .../Configuration/Configuration+Mock.swift | 6 +- .../Public/Glia/Glia+StartEngagement.swift | 39 ++++++ GliaWidgets/Sources/Theme/Theme+Call.swift | 2 +- GliaWidgets/Sources/Theme/Theme+Chat.swift | 2 +- .../Call/CallViewController.Mock.swift | 2 + .../Glia/GliaTests+StartEngagement.swift | 123 ++++++++++++++++++ GliaWidgetsTests/Sources/Glia/GliaTests.swift | 3 +- 8 files changed, 171 insertions(+), 14 deletions(-) diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index f9510c532..0a8ddefd6 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -1694,7 +1694,6 @@ isa = PBXGroup; children = ( 3146C9412AB1850A0047D8CC /* Resources */, - 7552DFB22A6FBC6E0093519B /* CoreSdk */, 7552DFAF2A6FB37E0093519B /* ChatMessage */, 846A5C3729D18D220049B29F /* ScreenShareHandler */, AFEF5C7229929A73005C3D8D /* SecureConversations */, @@ -2692,13 +2691,6 @@ path = ChatMessage; sourceTree = ""; }; - 7552DFB22A6FBC6E0093519B /* CoreSdk */ = { - isa = PBXGroup; - children = ( - ); - path = CoreSdk; - sourceTree = ""; - }; 755D186329A6A4B10009F5E8 /* WelcomeStyle */ = { isa = PBXGroup; children = ( diff --git a/GliaWidgets/Public/Configuration/Configuration+Mock.swift b/GliaWidgets/Public/Configuration/Configuration+Mock.swift index 95883ef39..409453c4a 100644 --- a/GliaWidgets/Public/Configuration/Configuration+Mock.swift +++ b/GliaWidgets/Public/Configuration/Configuration+Mock.swift @@ -7,12 +7,14 @@ extension Configuration { static func mock( authMethod: AuthorizationMethod = .siteApiKey(id: "site-api-key-id", secret: "site-api-key-secret"), environment: Environment = .beta, - site: String = "site-id" + site: String = "site-id", + companyName: String = "" ) -> Self { Configuration( authorizationMethod: authMethod, environment: environment, - site: site + site: site, + companyName: companyName ) } } diff --git a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift index 55423ccf5..d37f65e1c 100644 --- a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift +++ b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift @@ -46,6 +46,16 @@ extension Glia { interactor.queueIds = queueIds } + theme.chat.connect.queue.firstText = companyName( + using: interactor, + currentName: theme.chat.connect.queue.firstText + ) + + theme.call.connect.queue.firstText = companyName( + using: interactor, + currentName: theme.call.connect.queue.firstText + ) + let viewFactory = ViewFactory( with: theme, messageRenderer: messageRenderer, @@ -69,6 +79,35 @@ extension Glia { ) } + func companyName( + using interactor: Interactor, + currentName: String? + ) -> String { + // As the default value is empty, it means that the integrator + // has set a value on the theme itself. Return that same value. + if let currentName, !currentName.isEmpty { + return currentName + } + + let companyNameStringKey = "general.company_name" + + // Company name has been set on the custom locale. + if let remoteCompanyName = stringProviding?.getRemoteString(companyNameStringKey) { + return remoteCompanyName + } + // Integrator has not set a company name in the custom locale, + // but has set it on the configuration. + else if !interactor.configuration.companyName.isEmpty { + return interactor.configuration.companyName + } + // Integrator has not set a company name anywhere, use the default. + else { + // This will return the fallback value every time, because we have + // already determined that the remote string is empty. + return Localization.General.companyName + } + } + func startRootCoordinator( with interactor: Interactor, viewFactory: ViewFactory, diff --git a/GliaWidgets/Sources/Theme/Theme+Call.swift b/GliaWidgets/Sources/Theme/Theme+Call.swift index df7d96c9b..8b07db7d2 100644 --- a/GliaWidgets/Sources/Theme/Theme+Call.swift +++ b/GliaWidgets/Sources/Theme/Theme+Call.swift @@ -68,7 +68,7 @@ extension Theme { ) ) let queue = ConnectStatusStyle( - firstText: Localization.General.companyName, + firstText: "", firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, diff --git a/GliaWidgets/Sources/Theme/Theme+Chat.swift b/GliaWidgets/Sources/Theme/Theme+Chat.swift index 89592c4be..7f3d75f86 100644 --- a/GliaWidgets/Sources/Theme/Theme+Chat.swift +++ b/GliaWidgets/Sources/Theme/Theme+Chat.swift @@ -70,7 +70,7 @@ extension Theme { ) ) let queue = ConnectStatusStyle( - firstText: Localization.General.companyName, + firstText: "", firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, diff --git a/GliaWidgets/Sources/ViewController/Call/CallViewController.Mock.swift b/GliaWidgets/Sources/ViewController/Call/CallViewController.Mock.swift index 4af4c20d0..f0d35516e 100644 --- a/GliaWidgets/Sources/ViewController/Call/CallViewController.Mock.swift +++ b/GliaWidgets/Sources/ViewController/Call/CallViewController.Mock.swift @@ -43,6 +43,7 @@ extension CallViewController { startWith: startAction ) let theme = Theme.mock() + theme.call.connect.queue.firstText = "CompanyName" let viewFactEnv = ViewFactory.Environment.mock let viewFactory: ViewFactory = .mock( theme: theme, @@ -217,6 +218,7 @@ extension CallViewController { startWith: startAction ) let theme = Theme.mock() + theme.call.connect.queue.firstText = "CompanyName" let viewFactEnv = ViewFactory.Environment.mock let viewFactory: ViewFactory = .mock( theme: theme, diff --git a/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift b/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift index 5410d4d5c..e8a897498 100644 --- a/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift +++ b/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift @@ -51,4 +51,127 @@ extension GliaTests { XCTAssertTrue(interactor.isConfigurationPerformed) XCTAssertEqual(calls, [.configureWithInteractor, .configureWithConfiguration]) } + + func testCompanyNameIsReceivedFromTheme() throws { + var environment = Glia.Environment.failing + var resultingViewFactory: ViewFactory? + + environment.createRootCoordinator = { _, viewFactory, _, _, _, _, _ in + resultingViewFactory = viewFactory + + return .mock( + interactor: .mock(environment: .failing), + viewFactory: viewFactory, + sceneProvider: nil, + engagementKind: .none, + screenShareHandler: .mock, + features: [], + environment: .failing + ) + } + + let sdk = Glia(environment: environment) + + let theme = Theme() + theme.call.connect.queue.firstText = "Glia 1" + theme.chat.connect.queue.firstText = "Glia 2" + + try sdk.configure(with: .mock()) + try sdk.startEngagement(engagementKind: .chat, in: ["queueId"], theme: theme) + + let configuredSdkTheme = resultingViewFactory?.theme + XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Glia 1") + XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "Glia 2") + } + + func testCompanyNameIsReceivedFromRemoteStrings() throws { + var environment = Glia.Environment.failing + var resultingViewFactory: ViewFactory? + + environment.createRootCoordinator = { _, viewFactory, _, _, _, _, _ in + resultingViewFactory = viewFactory + + return .mock( + interactor: .mock(environment: .failing), + viewFactory: viewFactory, + sceneProvider: nil, + engagementKind: .none, + screenShareHandler: .mock, + features: [], + environment: .failing + ) + } + + environment.coreSdk.localeProvider.getRemoteString = { _ in "Glia" } + environment.coreSdk.configureWithInteractor = { _ in } + environment.coreSdk.configureWithConfiguration = { _, completion in + completion?() + } + environment.coreSdk.getCurrentEngagement = { nil } + + let sdk = Glia(environment: environment) + + try sdk.configure(with: .mock()) { } + try sdk.startEngagement(engagementKind: .chat, in: ["queueId"]) + + let configuredSdkTheme = resultingViewFactory?.theme + XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Glia") + XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "Glia") + } + + func testCompanyNameIsReceivedFromConfiguration() throws { + var environment = Glia.Environment.failing + var resultingViewFactory: ViewFactory? + + environment.createRootCoordinator = { _, viewFactory, _, _, _, _, _ in + resultingViewFactory = viewFactory + + return .mock( + interactor: .mock(environment: .failing), + viewFactory: viewFactory, + sceneProvider: nil, + engagementKind: .none, + screenShareHandler: .mock, + features: [], + environment: .failing + ) + } + + let sdk = Glia(environment: environment) + + try sdk.configure(with: .mock(companyName: "Glia")) + try sdk.startEngagement(engagementKind: .chat, in: ["queueId"]) + + let configuredSdkTheme = resultingViewFactory?.theme + XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Glia") + XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "Glia") + } + + func testCompanyNameIsReceivedFromLocalStrings() throws { + var environment = Glia.Environment.failing + var resultingViewFactory: ViewFactory? + + environment.createRootCoordinator = { _, viewFactory, _, _, _, _, _ in + resultingViewFactory = viewFactory + + return .mock( + interactor: .mock(environment: .failing), + viewFactory: viewFactory, + sceneProvider: nil, + engagementKind: .none, + screenShareHandler: .mock, + features: [], + environment: .failing + ) + } + + let sdk = Glia(environment: environment) + + try sdk.configure(with: .mock()) + try sdk.startEngagement(engagementKind: .chat, in: ["queueId"]) + + let configuredSdkTheme = resultingViewFactory?.theme + XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "CompanyName") + XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "CompanyName") + } } diff --git a/GliaWidgetsTests/Sources/Glia/GliaTests.swift b/GliaWidgetsTests/Sources/Glia/GliaTests.swift index 8fb2e2567..46dcde9ca 100644 --- a/GliaWidgetsTests/Sources/Glia/GliaTests.swift +++ b/GliaWidgetsTests/Sources/Glia/GliaTests.swift @@ -49,7 +49,7 @@ final class GliaTests: XCTestCase { gliaEnv.fileManager = fileManager gliaEnv.coreSdk.configureWithInteractor = { _ in } gliaEnv.createFileUploadListModel = { _ in .mock() } - + gliaEnv.coreSdk.localeProvider.getRemoteString = { _ in nil } gliaEnv.coreSdk.authentication = { _ in .mock } gliaEnv.coreSdk.configureWithConfiguration = { _, callback in callback?() } gliaEnv.coreSdk.queueForEngagement = { _, callback in @@ -284,4 +284,3 @@ final class GliaTests: XCTestCase { XCTAssertEqual(delegate.invokedEventCallParameterList, [.maximized]) } } - From a350389306fbae87bdcc70e29023a99f8d688e75 Mon Sep 17 00:00:00 2001 From: Egor Egorov Date: Thu, 28 Sep 2023 17:59:27 +0300 Subject: [PATCH 21/40] Localization updates Local key/value pairs were updated to align localization between platforms and remote default locale MOB-2719 --- GliaWidgets/Localization.swift | 528 +++++++++--------- .../Resources/en.lproj/Localizable.strings | 260 +++++---- ...heme+SecureConversationsConfirmation.swift | 2 +- .../Theme+SecureConversationsWelcome.swift | 32 +- .../View/ScreenSharingView.swift | 2 +- .../ViewModel/VideoCallViewModel.swift | 4 +- .../VisitorCode/VisitorCodeView.swift | 2 +- .../Extensions/String+TemplateString.swift | 2 +- GliaWidgets/Sources/Theme/Theme+Alert.swift | 2 +- .../Theme/Theme+AlertConfiguration.swift | 48 +- GliaWidgets/Sources/Theme/Theme+Call.swift | 53 +- GliaWidgets/Sources/Theme/Theme+Chat.swift | 54 +- .../Sources/Theme/Theme+ScreenSharing.swift | 6 +- .../Sources/Theme/Theme+VisitorCode.swift | 4 +- .../Survey/Survey.ViewController.Props.swift | 10 +- .../ViewModel/Call/CallViewModel.swift | 6 +- .../Mocks/CallButtonBarStyle.Mock.swift | 6 +- .../VideoCall/Mocks/HeaderStyle.Mock.swift | 2 +- .../Glia/GliaTests+StartEngagement.swift | 4 +- 19 files changed, 507 insertions(+), 520 deletions(-) diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index 995ab6b96..3e11b20b3 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -15,26 +15,42 @@ internal enum Localization { /// Settings internal static let settings = Localization.tr("Localizable", "alert.action.settings", fallback: "Settings") } + internal enum CameraAccess { + /// Unable to access camera + internal static let error = Localization.tr("Localizable", "alert.camera_access.error", fallback: "Unable to access camera") + } + internal enum MediaSourceAccess { + /// Unable to access media source + internal static let error = Localization.tr("Localizable", "alert.media_source_access.error", fallback: "Unable to access media source") + } + internal enum MicrophoneAccess { + /// Unable to access microphone + internal static let error = Localization.tr("Localizable", "alert.microphone_access.error", fallback: "Unable to access microphone") + } + internal enum ScreenSharing { + internal enum Start { + /// Start Screen Sharing + internal static let header = Localization.tr("Localizable", "alert.screen_sharing.start.header", fallback: "Start Screen Sharing") + /// {operatorName} has asked you to share your screen. + internal static let message = Localization.tr("Localizable", "alert.screen_sharing.start.message", fallback: "{operatorName} has asked you to share your screen.") + } + internal enum Stop { + /// Stop Screen Sharing? + internal static let header = Localization.tr("Localizable", "alert.screen_sharing.stop.header", fallback: "Stop Screen Sharing?") + /// Are you sure you want to stop sharing your screen? + internal static let message = Localization.tr("Localizable", "alert.screen_sharing.stop.message", fallback: "Are you sure you want to stop sharing your screen?") + } + } } internal enum Call { - /// On Hold - internal static let onHold = Localization.tr("Localizable", "call.on_hold", fallback: "On Hold") internal enum Bubble { internal enum Accessibility { - /// Deactivates minimize. - internal static let hint = Localization.tr("Localizable", "call.bubble.accessibility.hint", fallback: "Deactivates minimize.") - /// Operator Avatar - internal static let label = Localization.tr("Localizable", "call.bubble.accessibility.label", fallback: "Operator Avatar") + /// Expands call view. + internal static let hint = Localization.tr("Localizable", "call.bubble.accessibility.hint", fallback: "Expands call view.") + /// Go back to the engagement. + internal static let label = Localization.tr("Localizable", "call.bubble.accessibility.label", fallback: "Go back to the engagement.") } } - internal enum Button { - /// Mute - internal static let mute = Localization.tr("Localizable", "call.button.mute", fallback: "Mute") - /// Speaker - internal static let speaker = Localization.tr("Localizable", "call.button.speaker", fallback: "Speaker") - /// Unmute - internal static let unmute = Localization.tr("Localizable", "call.button.unmute", fallback: "Unmute") - } internal enum Buttons { internal enum Chat { internal enum BadgeValue { @@ -67,48 +83,64 @@ internal enum Localization { } } } + internal enum Duration { + internal enum Accessibility { + /// Call duration. + internal static let label = Localization.tr("Localizable", "call.duration.accessibility.label", fallback: "Call duration.") + } + } internal enum Header { internal enum Back { internal enum Button { internal enum Accessibility { - /// Activates minimize. - internal static let hint = Localization.tr("Localizable", "call.header.back.button.accessibility.hint", fallback: "Activates minimize.") + /// Minimizes call view. + internal static let hint = Localization.tr("Localizable", "call.header.back.button.accessibility.hint", fallback: "Minimizes call view.") } } } } + internal enum Mute { + /// Mute + internal static let button = Localization.tr("Localizable", "call.mute.button", fallback: "Mute") + } internal enum OnHold { /// You can continue browsing while you are on hold - internal static let bottomText = Localization.tr("Localizable", "call.onHold.bottom_text", fallback: "You can continue browsing while you are on hold") + internal static let bottomText = Localization.tr("Localizable", "call.on_hold.bottom_text", fallback: "You can continue browsing while you are on hold") + /// On Hold + internal static let icon = Localization.tr("Localizable", "call.on_hold.icon", fallback: "On Hold") } - internal enum Operator { - internal enum Avatar { - internal enum Accessibility { - /// Displays operator avatar or placeholder. - internal static let hint = Localization.tr("Localizable", "call.operator.avatar.accessibility.hint", fallback: "Displays operator avatar or placeholder.") - /// Operator Avatar - internal static let label = Localization.tr("Localizable", "call.operator.avatar.accessibility.label", fallback: "Operator Avatar") - } + internal enum OperatorAvatar { + internal enum Accessibility { + /// Shows operator picture. + internal static let hint = Localization.tr("Localizable", "call.operator_avatar.accessibility.hint", fallback: "Shows operator picture.") + /// Operator Picture + internal static let label = Localization.tr("Localizable", "call.operator_avatar.accessibility.label", fallback: "Operator Picture") } } internal enum OperatorName { internal enum Accessibility { - /// Displays operator name. - internal static let hint = Localization.tr("Localizable", "call.operator_name.accessibility.hint", fallback: "Displays operator name.") + /// Shows operator name. + internal static let hint = Localization.tr("Localizable", "call.operator_name.accessibility.hint", fallback: "Shows operator name.") } } - internal enum Video { - internal enum Operator { - internal enum Accessibility { - /// Operator's Video - internal static let label = Localization.tr("Localizable", "call.video.operator.accessibility.label", fallback: "Operator's Video") - } + internal enum OperatorVideo { + internal enum Accessibility { + /// Operator's Video + internal static let label = Localization.tr("Localizable", "call.operator_video.accessibility.label", fallback: "Operator's Video") } - internal enum Visitor { - internal enum Accessibility { - /// Your Video - internal static let label = Localization.tr("Localizable", "call.video.visitor.accessibility.label", fallback: "Your Video") - } + } + internal enum Speaker { + /// Speaker + internal static let button = Localization.tr("Localizable", "call.speaker.button", fallback: "Speaker") + } + internal enum Unmute { + /// Unmute + internal static let button = Localization.tr("Localizable", "call.unmute.button", fallback: "Unmute") + } + internal enum VisitorVideo { + internal enum Accessibility { + /// Your Video + internal static let label = Localization.tr("Localizable", "call.visitor_video.accessibility.label", fallback: "Your Video") } } } @@ -116,38 +148,32 @@ internal enum Localization { internal enum ScreenSharing { /// Your Screen is Being Shared internal static let message = Localization.tr("Localizable", "call_visualizer.screen_sharing.message", fallback: "Your Screen is Being Shared") - /// Screen Sharing - internal static let title = Localization.tr("Localizable", "call_visualizer.screen_sharing.title", fallback: "Screen Sharing") + internal enum Header { + /// Screen Sharing + internal static let title = Localization.tr("Localizable", "call_visualizer.screen_sharing.header.title", fallback: "Screen Sharing") + } } internal enum VisitorCode { /// Your Visitor Code internal static let title = Localization.tr("Localizable", "call_visualizer.visitor_code.title", fallback: "Your Visitor Code") - internal enum Action { - /// Close - internal static let close = Localization.tr("Localizable", "call_visualizer.visitor_code.action.close", fallback: "Close") - /// Refresh - internal static let refresh = Localization.tr("Localizable", "call_visualizer.visitor_code.action.refresh", fallback: "Refresh") - } internal enum Close { internal enum Accessibility { - /// Closes visitor code - internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.close.accessibility.hint", fallback: "Closes visitor code") - /// Close Button - internal static let label = Localization.tr("Localizable", "call_visualizer.visitor_code.close.accessibility.label", fallback: "Close Button") + /// Closes the visitor code + internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.close.accessibility.hint", fallback: "Closes the visitor code") } } internal enum Refresh { internal enum Accessibility { - /// Generates new visitor code - internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.hint", fallback: "Generates new visitor code") + /// Generates a new visitor code + internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.hint", fallback: "Generates a new visitor code") /// Refresh Button internal static let label = Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.label", fallback: "Refresh Button") } } internal enum Title { internal enum Accessibility { - /// Your five-digit visitor code is - internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.title.accessibility.hint", fallback: "Your five-digit visitor code is") + /// Shows the five-digit visitor code. + internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.title.accessibility.hint", fallback: "Shows the five-digit visitor code.") } } } @@ -155,8 +181,6 @@ internal enum Localization { internal enum Chat { /// Pick attachment internal static let attachFiles = Localization.tr("Localizable", "chat.attach_files", fallback: "Pick attachment") - /// {operatorName} has joined the conversation. - internal static let operatorJoined = Localization.tr("Localizable", "chat.operator_joined", fallback: "{operatorName} has joined the conversation.") /// New Messages internal static let unreadMessageDivider = Localization.tr("Localizable", "chat.unread_message_divider", fallback: "New Messages") internal enum Attachment { @@ -164,18 +188,18 @@ internal enum Localization { internal static let photoLibrary = Localization.tr("Localizable", "chat.attachment.photo_library", fallback: "Photo Library") /// Take Photo or Video internal static let takePhoto = Localization.tr("Localizable", "chat.attachment.take_photo", fallback: "Take Photo or Video") + /// This file type is not supported. + internal static let unsupportedFile = Localization.tr("Localizable", "chat.attachment.unsupported_file", fallback: "This file type is not supported.") internal enum Message { internal enum Accessibility { /// Attachment from {fileSender} internal static let label = Localization.tr("Localizable", "chat.attachment.message.accessibility.label", fallback: "Attachment from {fileSender}") } } - internal enum Upload { - /// Invalid file type! - internal static let unsupportedFile = Localization.tr("Localizable", "chat.attachment.upload.unsupported_file", fallback: "Invalid file type!") - } } internal enum ChoiceCard { + /// Tap on the answer above + internal static let placeholderMessage = Localization.tr("Localizable", "chat.choice_card.placeholder_message", fallback: "Tap on the answer above") internal enum Button { internal enum Disabled { internal enum Accessibility { @@ -192,35 +216,37 @@ internal enum Localization { } } internal enum Download { - /// Download - internal static let download = Localization.tr("Localizable", "chat.download.download", fallback: "Download") /// Downloading file… internal static let downloading = Localization.tr("Localizable", "chat.download.downloading", fallback: "Downloading file…") - /// Download failed - internal static let failed = Localization.tr("Localizable", "chat.download.failed", fallback: "Download failed") - } - internal enum Duration { - internal enum Accessibility { - /// Displays call duration. - internal static let label = Localization.tr("Localizable", "chat.duration.accessibility.label", fallback: "Displays call duration.") - } + /// Could not download the file. + internal static let failed = Localization.tr("Localizable", "chat.download.failed", fallback: "Could not download the file.") } internal enum File { - /// Failed to confirm the safety of the file. - internal static let infectedError = Localization.tr("Localizable", "chat.file.infected_error", fallback: "Failed to confirm the safety of the file.") - /// File size over 25MB limit! - internal static let tooLargeError = Localization.tr("Localizable", "chat.file.too_large_error", fallback: "File size over 25MB limit!") + internal enum InfectedFile { + /// The safety of the file could not be confirmed. + internal static let error = Localization.tr("Localizable", "chat.file.infected_file.error", fallback: "The safety of the file could not be confirmed.") + } + internal enum RemoveUpload { + internal enum Accessibility { + /// Remove upload + internal static let label = Localization.tr("Localizable", "chat.file.remove_upload.accessibility.label", fallback: "Remove upload") + } + } + internal enum SizeLimit { + /// File size must be less than 25 MB. + internal static let error = Localization.tr("Localizable", "chat.file.size_limit.error", fallback: "File size must be less than 25 MB.") + } internal enum Upload { - /// Uploading failed - internal static let failed = Localization.tr("Localizable", "chat.file.upload.failed", fallback: "Uploading failed") - /// Failed to upload. - internal static let genericError = Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Failed to upload.") + /// Could not upload the file. + internal static let failed = Localization.tr("Localizable", "chat.file.upload.failed", fallback: "Could not upload the file.") + /// Could not upload the file. + internal static let genericError = Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Could not upload the file.") /// Uploading file… internal static let inProgress = Localization.tr("Localizable", "chat.file.upload.in_progress", fallback: "Uploading file…") - /// Network error. - internal static let networkError = Localization.tr("Localizable", "chat.file.upload.network_error", fallback: "Network error.") - /// Checking safety of the file… - internal static let scanning = Localization.tr("Localizable", "chat.file.upload.scanning", fallback: "Checking safety of the file…") + /// Could not upload the file due to a network issue. + internal static let networkError = Localization.tr("Localizable", "chat.file.upload.network_error", fallback: "Could not upload the file due to a network issue.") + /// Checking file security… + internal static let scanning = Localization.tr("Localizable", "chat.file.upload.scanning", fallback: "Checking file security…") /// Ready to send internal static let success = Localization.tr("Localizable", "chat.file.upload.success", fallback: "Ready to send") } @@ -228,12 +254,20 @@ internal enum Localization { internal enum Input { /// Enter Message internal static let placeholder = Localization.tr("Localizable", "chat.input.placeholder", fallback: "Enter Message") - /// Send - internal static let send = Localization.tr("Localizable", "chat.input.send", fallback: "Send") + } + internal enum MediaUpgrade { + internal enum Audio { + /// Upgraded to Audio + internal static let systemMessage = Localization.tr("Localizable", "chat.media_upgrade.audio.system_message", fallback: "Upgraded to Audio") + } + internal enum Video { + /// Upgraded to Video + internal static let systemMessage = Localization.tr("Localizable", "chat.media_upgrade.video.system_message", fallback: "Upgraded to Video") + } } internal enum Message { - /// Tap on the answer above - internal static let choiceCardPlaceholder = Localization.tr("Localizable", "chat.message.choice_card_placeholder", fallback: "Tap on the answer above") + /// Delivered + internal static let delivered = Localization.tr("Localizable", "chat.message.delivered", fallback: "Delivered") /// Send a message to start chatting internal static let startEngagementPlaceholder = Localization.tr("Localizable", "chat.message.start_engagement_placeholder", fallback: "Send a message to start chatting") internal enum Unread { @@ -243,25 +277,25 @@ internal enum Localization { } } } - internal enum Operator { - internal enum Avatar { - internal enum Accessibility { - /// Avatar - internal static let label = Localization.tr("Localizable", "chat.operator.avatar.accessibility.label", fallback: "Avatar") - } + internal enum OperatorAvatar { + internal enum Accessibility { + /// Operator Picture + internal static let label = Localization.tr("Localizable", "chat.operator_avatar.accessibility.label", fallback: "Operator Picture") } - internal enum Name { - internal enum Accessibility { - /// Displays operator name. - internal static let label = Localization.tr("Localizable", "chat.operator.name.accessibility.label", fallback: "Displays operator name.") - } + } + internal enum OperatorJoined { + /// {operatorName} has joined the conversation. + internal static let systemMessage = Localization.tr("Localizable", "chat.operator_joined.system_message", fallback: "{operatorName} has joined the conversation.") + } + internal enum OperatorName { + internal enum Accessibility { + /// Operator Name + internal static let label = Localization.tr("Localizable", "chat.operator_name.accessibility.label", fallback: "Operator Name") } } internal enum Status { - /// Delivered - internal static let delivered = Localization.tr("Localizable", "chat.status.delivered", fallback: "Delivered") - /// Operator typing - internal static let typing = Localization.tr("Localizable", "chat.status.typing", fallback: "Operator typing") + /// Operator is typing + internal static let typing = Localization.tr("Localizable", "chat.status.typing", fallback: "Operator is typing") internal enum Typing { internal enum Accessibility { /// {operatorName} is typing @@ -269,69 +303,27 @@ internal enum Localization { } } } - internal enum Upgrade { - internal enum Audio { - /// Upgraded to Audio Call - internal static let text = Localization.tr("Localizable", "chat.upgrade.audio.text", fallback: "Upgraded to Audio Call") - } - internal enum Video { - /// Upgraded to Video Call - internal static let text = Localization.tr("Localizable", "chat.upgrade.video.text", fallback: "Upgraded to Video Call") - } - } - internal enum Upload { - internal enum Remove { - internal enum Accessibility { - /// Remove upload - internal static let label = Localization.tr("Localizable", "chat.upload.remove.accessibility.label", fallback: "Remove upload") - } - } - } } internal enum Engagement { /// Operator - internal static let defaultOperatorName = Localization.tr("Localizable", "engagement.default_operator_name", fallback: "Operator") - /// Minimize - internal static let minimizeVideoButton = Localization.tr("Localizable", "engagement.minimize_video_button", fallback: "Minimize") - /// {operatorName} has offered you to upgrade - internal static let offerUpgrade = Localization.tr("Localizable", "engagement.offer_upgrade", fallback: "{operatorName} has offered you to upgrade") - internal enum Alert { - internal enum Camera { - /// Unable to access camera - internal static let header = Localization.tr("Localizable", "engagement.alert.camera.header", fallback: "Unable to access camera") - } - internal enum MediaSource { - /// Unable to access media source - internal static let header = Localization.tr("Localizable", "engagement.alert.media_source.header", fallback: "Unable to access media source") - } - internal enum Microphone { - /// Unable to access microphone - internal static let header = Localization.tr("Localizable", "engagement.alert.microphone.header", fallback: "Unable to access microphone") - } - internal enum ScreenSharing { - internal enum Start { - /// {operatorName} has asked you to share your screen - internal static let header = Localization.tr("Localizable", "engagement.alert.screen_sharing.start.header", fallback: "{operatorName} has asked you to share your screen") - /// {operatorName} would like to see the screen of your device - internal static let message = Localization.tr("Localizable", "engagement.alert.screen_sharing.start.message", fallback: "{operatorName} would like to see the screen of your device") - } - internal enum Stop { - /// Stop screen sharing? - internal static let header = Localization.tr("Localizable", "engagement.alert.screen_sharing.stop.header", fallback: "Stop screen sharing?") - /// Are you sure you want to stop sharing your screen? - internal static let message = Localization.tr("Localizable", "engagement.alert.screen_sharing.stop.message", fallback: "Are you sure you want to stop sharing your screen?") - } - } + internal static let defaultOperator = Localization.tr("Localizable", "engagement.default_operator", fallback: "Operator") + internal enum Audio { + /// Audio + internal static let title = Localization.tr("Localizable", "engagement.audio.title", fallback: "Audio") } - internal enum Connect { - /// We are here to help! - internal static let placeholder = Localization.tr("Localizable", "engagement.connect.placeholder", fallback: "We are here to help!") + internal enum Chat { + /// Chat + internal static let title = Localization.tr("Localizable", "engagement.chat.title", fallback: "Chat") + } + internal enum ConnectionScreen { /// Connecting with {operatorName} - internal static let with = Localization.tr("Localizable", "engagement.connect.with", fallback: "Connecting with {operatorName}") + internal static let connectWith = Localization.tr("Localizable", "engagement.connection_screen.connect_with", fallback: "Connecting with {operatorName}") + /// We are here to help! + internal static let message = Localization.tr("Localizable", "engagement.connection_screen.message", fallback: "We are here to help!") } internal enum End { - /// Are you sure you want to end engagement? - internal static let message = Localization.tr("Localizable", "engagement.end.message", fallback: "Are you sure you want to end engagement?") + /// Are you sure you want to end this engagement? + internal static let message = Localization.tr("Localizable", "engagement.end.message", fallback: "Are you sure you want to end this engagement?") internal enum Confirmation { /// End Engagement? internal static let header = Localization.tr("Localizable", "engagement.end.confirmation.header", fallback: "End Engagement?") @@ -345,35 +337,45 @@ internal enum Localization { internal static let message = Localization.tr("Localizable", "engagement.ended.message", fallback: "This engagement has ended.\nThank you!") } internal enum MediaUpgrade { + /// {operatorName} has offered you to upgrade. + internal static let offer = Localization.tr("Localizable", "engagement.media_upgrade.offer", fallback: "{operatorName} has offered you to upgrade.") internal enum Audio { /// Speak through your device internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.audio.info", fallback: "Speak through your device") } internal enum Phone { - /// Enter your number and we'll call you - internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.phone.info", fallback: "Enter your number and we'll call you") + /// Enter your number and will call you back. + internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.phone.info", fallback: "Enter your number and will call you back.") } } - internal enum QueueClosed { - /// We're sorry - internal static let header = Localization.tr("Localizable", "engagement.queue_closed.header", fallback: "We're sorry") - /// Operators are no longer available. - /// Please try again later. - internal static let message = Localization.tr("Localizable", "engagement.queue_closed.message", fallback: "Operators are no longer available. \nPlease try again later.") + internal enum MinimizeVideo { + /// Minimize + internal static let button = Localization.tr("Localizable", "engagement.minimize_video.button", fallback: "Minimize") } - internal enum QueueLeave { - /// Are you sure you want to leave? - internal static let header = Localization.tr("Localizable", "engagement.queue_leave.header", fallback: "Are you sure you want to leave?") - /// You will lose your place in the queue. - internal static let message = Localization.tr("Localizable", "engagement.queue_leave.message", fallback: "You will lose your place in the queue.") - } - internal enum QueueReconnectionFailed { - /// Please try again later. - internal static let tryAgain = Localization.tr("Localizable", "engagement.queue_reconnection_failed.try_again", fallback: "Please try again later.") + internal enum Phone { + /// Phone + internal static let title = Localization.tr("Localizable", "engagement.phone.title", fallback: "Phone") } - internal enum QueueTransferring { + internal enum Queue { /// Transferring - internal static let message = Localization.tr("Localizable", "engagement.queue_transferring.message", fallback: "Transferring") + internal static let transferring = Localization.tr("Localizable", "engagement.queue.transferring", fallback: "Transferring") + internal enum Closed { + /// We are sorry! The queue is closed. + internal static let header = Localization.tr("Localizable", "engagement.queue.closed.header", fallback: "We are sorry! The queue is closed.") + /// Operators are no longer available. + /// Please try again later. + internal static let message = Localization.tr("Localizable", "engagement.queue.closed.message", fallback: "Operators are no longer available. \nPlease try again later.") + } + internal enum Leave { + /// Are you sure you want to leave? + internal static let header = Localization.tr("Localizable", "engagement.queue.leave.header", fallback: "Are you sure you want to leave?") + /// You will lose your place in the queue. + internal static let message = Localization.tr("Localizable", "engagement.queue.leave.message", fallback: "You will lose your place in the queue.") + } + internal enum Reconnection { + /// Please try again later. + internal static let failed = Localization.tr("Localizable", "engagement.queue.reconnection.failed", fallback: "Please try again later.") + } } internal enum QueueWait { /// You can continue browsing and we will connect you automatically. @@ -383,16 +385,18 @@ internal enum Localization { /// Messaging internal static let title = Localization.tr("Localizable", "engagement.secure_messaging.title", fallback: "Messaging") } + internal enum Video { + /// Video + internal static let title = Localization.tr("Localizable", "engagement.video.title", fallback: "Video") + } } internal enum Error { - /// Something went wrong - internal static let general = Localization.tr("Localizable", "error.general", fallback: "Something went wrong") - /// Internal error - internal static let `internal` = Localization.tr("Localizable", "error.internal", fallback: "Internal error") - internal enum Unexpected { - /// We're sorry, there has been an unexpected error. - internal static let title = Localization.tr("Localizable", "error.unexpected.title", fallback: "We're sorry, there has been an unexpected error.") - } + /// Something went wrong. + internal static let general = Localization.tr("Localizable", "error.general", fallback: "Something went wrong.") + /// Something went wrong. + internal static let `internal` = Localization.tr("Localizable", "error.internal", fallback: "Something went wrong.") + /// Something went wrong. + internal static let unexpected = Localization.tr("Localizable", "error.unexpected", fallback: "Something went wrong.") } internal enum General { /// Accept @@ -407,8 +411,8 @@ internal enum Localization { internal static let close = Localization.tr("Localizable", "general.close", fallback: "Close") /// Comment internal static let comment = Localization.tr("Localizable", "general.comment", fallback: "Comment") - /// CompanyName - internal static let companyName = Localization.tr("Localizable", "general.company_name", fallback: "CompanyName") + /// Company Name + internal static let companyName = Localization.tr("Localizable", "general.company_name", fallback: "Company Name") /// Decline internal static let decline = Localization.tr("Localizable", "general.decline", fallback: "Decline") /// Download @@ -424,11 +428,17 @@ internal enum Localization { /// Open internal static let `open` = Localization.tr("Localizable", "general.open", fallback: "Open") /// Powered by - internal static let poweredBy = Localization.tr("Localizable", "general.powered_by", fallback: "Powered by") + internal static let powered = Localization.tr("Localizable", "general.powered", fallback: "Powered by") + /// Refresh + internal static let refresh = Localization.tr("Localizable", "general.refresh", fallback: "Refresh") /// Retry internal static let retry = Localization.tr("Localizable", "general.retry", fallback: "Retry") /// Selected internal static let selected = Localization.tr("Localizable", "general.selected", fallback: "Selected") + /// Send + internal static let send = Localization.tr("Localizable", "general.send", fallback: "Send") + /// Sending… + internal static let sending = Localization.tr("Localizable", "general.sending", fallback: "Sending…") /// Submit internal static let submit = Localization.tr("Localizable", "general.submit", fallback: "Submit") /// Thank you! @@ -437,54 +447,56 @@ internal enum Localization { internal static let yes = Localization.tr("Localizable", "general.yes", fallback: "Yes") /// You internal static let you = Localization.tr("Localizable", "general.you", fallback: "You") + internal enum Close { + /// Close Button + internal static let accessibility = Localization.tr("Localizable", "general.close.accessibility", fallback: "Close Button") + } } internal enum Gva { - /// This action is not currently supported on mobile. - internal static let errorUnsupported = Localization.tr("Localizable", "gva.error_unsupported", fallback: "This action is not currently supported on mobile.") + internal enum UnsupportedAction { + /// This action is not currently supported on mobile. + internal static let error = Localization.tr("Localizable", "gva.unsupported_action.error", fallback: "This action is not currently supported on mobile.") + } } internal enum Ios { - internal enum Engagement { - internal enum Alert { - internal enum Camera { - /// Allow access to your camera from device menu: “Settings” - “Privacy” - “Camera” - internal static let message = Localization.tr("Localizable", "ios.engagement.alert.camera.message", fallback: "Allow access to your camera from device menu: “Settings” - “Privacy” - “Camera”") - } - internal enum MediaSource { - /// This media source is not available on your device - internal static let message = Localization.tr("Localizable", "ios.engagement.alert.media_source.message", fallback: "This media source is not available on your device") - } - internal enum Microphone { - /// Allow access to your microphone from device menu: “Settings” - “Privacy” - “Microphone” - internal static let message = Localization.tr("Localizable", "ios.engagement.alert.microphone.message", fallback: "Allow access to your microphone from device menu: “Settings” - “Privacy” - “Microphone”") - } + internal enum Alert { + internal enum CameraAccess { + /// Allow access to your camera in 'Settings' - 'Privacy & Security' - 'Camera' + internal static let message = Localization.tr("Localizable", "ios.alert.camera_access.message", fallback: "Allow access to your camera in 'Settings' - 'Privacy & Security' - 'Camera'") + } + internal enum MediaSource { + /// This media source is not available on your device + internal static let message = Localization.tr("Localizable", "ios.alert.media_source.message", fallback: "This media source is not available on your device") } - internal enum QueueWait { - /// (By default your video will be off) - internal static let videoNotice = Localization.tr("Localizable", "ios.engagement.queue_wait.video_notice", fallback: "(By default your video will be off)") + internal enum MicrophoneAccess { + /// Allow access to your microphone in 'Settings' - 'Privacy & Security' - 'Microphone' + internal static let message = Localization.tr("Localizable", "ios.alert.microphone_access.message", fallback: "Allow access to your microphone in 'Settings' - 'Privacy & Security' - 'Microphone'") + } + } + internal enum Engagement { + internal enum ConnectionScreen { + /// (By default, your video will be turned off) + internal static let videoNotice = Localization.tr("Localizable", "ios.engagement.connection_screen.video_notice", fallback: "(By default, your video will be turned off)") } } } - internal enum Media { + internal enum MediaUpgrade { internal enum Audio { - /// Audio - internal static let name = Localization.tr("Localizable", "media.audio.name", fallback: "Audio") - } - internal enum Phone { - /// Phone - internal static let name = Localization.tr("Localizable", "media.phone.name", fallback: "Phone") - } - internal enum Text { - /// Chat - internal static let name = Localization.tr("Localizable", "media.text.name", fallback: "Chat") + /// {operatorName} has offered you to upgrade to audio + internal static let title = Localization.tr("Localizable", "media_upgrade.audio.title", fallback: "{operatorName} has offered you to upgrade to audio") } internal enum Video { - /// Video - internal static let name = Localization.tr("Localizable", "media.video.name", fallback: "Video") + internal enum OneWay { + /// {operatorName} has offered you to see their video + internal static let title = Localization.tr("Localizable", "media_upgrade.video.one_way.title", fallback: "{operatorName} has offered you to see their video") + } + internal enum TwoWay { + /// {operatorName} has offered you to upgrade to video + internal static let title = Localization.tr("Localizable", "media_upgrade.video.two_way.title", fallback: "{operatorName} has offered you to upgrade to video") + } } } internal enum MessageCenter { - /// Check messages - internal static let checkMessages = Localization.tr("Localizable", "message_center.check_messages", fallback: "Check messages") /// Messaging internal static let header = Localization.tr("Localizable", "message_center.header", fallback: "Messaging") internal enum Confirmation { @@ -510,12 +522,12 @@ internal enum Localization { internal static let title = Localization.tr("Localizable", "message_center.unavailable.title", fallback: "Message Center Unavailable") } internal enum Welcome { - /// The message cannot exceed 10000 characters. - internal static let messageLengthWarning = Localization.tr("Localizable", "message_center.welcome.message_length_warning", fallback: "The message cannot exceed 10000 characters.") + /// Check messages + internal static let checkMessages = Localization.tr("Localizable", "message_center.welcome.check_messages", fallback: "Check messages") /// Your message internal static let messageTitle = Localization.tr("Localizable", "message_center.welcome.message_title", fallback: "Your message") - /// Send a message and we’ll get back to you within 48 hours - internal static let subtitle = Localization.tr("Localizable", "message_center.welcome.subtitle", fallback: "Send a message and we’ll get back to you within 48 hours") + /// Send a message and we will get back to you within 48 hours. + internal static let subtitle = Localization.tr("Localizable", "message_center.welcome.subtitle", fallback: "Send a message and we will get back to you within 48 hours.") /// Welcome to Message Center internal static let title = Localization.tr("Localizable", "message_center.welcome.title", fallback: "Welcome to Message Center") internal enum CheckMessages { @@ -532,9 +544,13 @@ internal enum Localization { internal static let label = Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.label", fallback: "File picker") } } - internal enum MessageTextView { + internal enum MessageInput { /// Enter your message - internal static let placeholder = Localization.tr("Localizable", "message_center.welcome.message_text_view.placeholder", fallback: "Enter your message") + internal static let placeholder = Localization.tr("Localizable", "message_center.welcome.message_input.placeholder", fallback: "Enter your message") + } + internal enum MessageLength { + /// The message cannot exceed 10,000 characters. + internal static let error = Localization.tr("Localizable", "message_center.welcome.message_length.error", fallback: "The message cannot exceed 10,000 characters.") } internal enum Send { internal enum Accessibility { @@ -546,13 +562,15 @@ internal enum Localization { } internal enum ScreenSharing { internal enum VisitorScreen { - /// End Screen Sharing - internal static let end = Localization.tr("Localizable", "screen_sharing.visitor_screen.end", fallback: "End Screen Sharing") internal enum Disclaimer { + /// Depending on your selection, your entire screen might be shared with the operator, not just the application window. + internal static let info = Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.info", fallback: "Depending on your selection, your entire screen might be shared with the operator, not just the application window.") /// You are about to share your screen internal static let title = Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.title", fallback: "You are about to share your screen") } internal enum End { + /// End Screen Sharing + internal static let title = Localization.tr("Localizable", "screen_sharing.visitor_screen.end.title", fallback: "End Screen Sharing") internal enum Accessibility { /// Ends screen sharing internal static let hint = Localization.tr("Localizable", "screen_sharing.visitor_screen.end.accessibility.hint", fallback: "Ends screen sharing") @@ -560,26 +578,18 @@ internal enum Localization { } } } - internal enum Screensharing { - internal enum VisitorScreen { - internal enum Disclaimer { - /// Depending on your selection, your entire screen might be shared with the operator, not just the application window. - internal static let info = Localization.tr("Localizable", "screensharing.visitor_screen.disclaimer.info", fallback: "Depending on your selection, your entire screen might be shared with the operator, not just the application window.") - } - } - } - internal enum SendMessage { - /// Send message - internal static let send = Localization.tr("Localizable", "send_message.send", fallback: "Send message") - /// Sending… - internal static let sending = Localization.tr("Localizable", "send_message.sending", fallback: "Sending…") - } internal enum Survey { internal enum Action { /// Please provide an answer. internal static let validationError = Localization.tr("Localizable", "survey.action.validation_error", fallback: "Please provide an answer.") } internal enum Question { + internal enum Input { + internal enum Accessibility { + /// Enter the answer + internal static let hint = Localization.tr("Localizable", "survey.question.input.accessibility.hint", fallback: "Enter the answer") + } + } internal enum OptionButton { internal enum Selected { internal enum Accessibility { @@ -594,44 +604,22 @@ internal enum Localization { } } } - internal enum TextField { - internal enum Accessibility { - /// Enter the answer - internal static let hint = Localization.tr("Localizable", "survey.question.text_field.accessibility.hint", fallback: "Enter the answer") - } - } - internal enum Title { + internal enum Required { internal enum Accessibility { - /// Required - internal static let label = Localization.tr("Localizable", "survey.question.title.accessibility.label", fallback: "Required") + /// This is a required question. + internal static let label = Localization.tr("Localizable", "survey.question.required.accessibility.label", fallback: "This is a required question.") } } } internal enum Validation { internal enum Title { internal enum Accessibility { - /// Please provide an answer for question above - internal static let label = Localization.tr("Localizable", "survey.validation.title.accessibility.label", fallback: "Please provide an answer for question above") + /// Please provide an answer for the question above. + internal static let label = Localization.tr("Localizable", "survey.validation.title.accessibility.label", fallback: "Please provide an answer for the question above.") } } } } - internal enum Upgrade { - internal enum Audio { - /// {operatorName} has offered you to upgrade to audio - internal static let title = Localization.tr("Localizable", "upgrade.audio.title", fallback: "{operatorName} has offered you to upgrade to audio") - } - internal enum Video { - internal enum OneWay { - /// {operatorName} has offered you to see their video - internal static let title = Localization.tr("Localizable", "upgrade.video.one_way.title", fallback: "{operatorName} has offered you to see their video") - } - internal enum TwoWay { - /// {operatorName} has offered you to upgrade to video - internal static let title = Localization.tr("Localizable", "upgrade.video.two_way.title", fallback: "{operatorName} has offered you to upgrade to video") - } - } - } internal enum VisitorCode { /// Could not load the visitor code. Please try refreshing. internal static let failed = Localization.tr("Localizable", "visitor_code.failed", fallback: "Could not load the visitor code. Please try refreshing.") diff --git a/GliaWidgets/Resources/en.lproj/Localizable.strings b/GliaWidgets/Resources/en.lproj/Localizable.strings index af2ef409e..90675244e 100644 --- a/GliaWidgets/Resources/en.lproj/Localizable.strings +++ b/GliaWidgets/Resources/en.lproj/Localizable.strings @@ -1,178 +1,175 @@ "alert.action.settings" = "Settings"; +"android_file_select_picture_title" = "Select picture"; +"android_file_select_file_title" = "Select file"; "android_app_bar_end_engagement_accessibility_label" = "End engagement"; "android_app_bar_nav_up_accessibility" = "Navigate Up"; -"android_bubble_accessibility" = "Back to the Engagement. Floating Button."; -"android_call_mute_accessibility" = "Unmute microphone"; -"android_call_on_hold_accessibility" = "Operator on hold"; -"android_call_speaker_off_accessibility" = "Turn on speaker"; -"android_call_speaker_on_accessibility" = "Turn off speaker"; -"android_call_unmute_accessibility" = "Mute microphone"; -"android_call_video_off_accessibility" = "Turn on video"; -"android_call_video_on_accessibility" = "Turn off video"; +"android_bubble_accessibility" = "Go back to the engagement."; +"android_call_mute_button_accessibility" = "Mute yourself"; +"android_call_on_hold_icon_accessibility" = "Your call is on hold"; +"android_call_turn_speaker_on_button_accessibility" = "Turn on the speaker"; +"android_call_turn_speaker_off_button_accessibility" = "Turn off the speaker"; +"android_call_unmute_button_accessibility" = "Unmute yourself"; +"android_call_turn_video_on_button_accessibility" = "Turn on your camera"; +"android_call_turn_video_off_button_accessibility" = "Turn off your camera"; "android_call_queue_message" = "An operator will be with you shortly."; -"android_chat_audio_accessibility_icon" = "Audio icon"; "android_chat_file_accessibility" = "Attachment %1$s, size %2$s. %3$s"; -"android_chat_file_operator_accessibility" = "Operator\'s attached file %1$s, size %2$s"; -"android_chat_accesandroid_chat_file_visitor_accessibilitysibility_file_visitor" = "Your attached file %1$s, size %2$s"; -"android_chat_file_visitor_delivered_accessibility" = "Your attached file %1$s, size %2$s. \n Delivered"; -"android_chat_accessibility_message" = "Operator\'s message: %1$s"; -"android_chat_operator_accessibility_image" = "Operator\'s attached image"; +"android_chat_operator_file_accessibility" = "Operator\'s attached file %1$s, size %2$s"; +"android_chat_visitor_file_accessibility" = "Your attached file %1$s, size %2$s"; +"android_notification_one_way_video_message" = "The operator’s camera is on. You can now see and hear them."; +"android_notification_one_way_video_no_audio_message" = "The operator’s camera is on. You can now see them."; +"android_notification_two_way_video_message" = "The video exchange is on. You and the operator can see and hear each other."; +"android_notification_two_way_video_no_audio_message" = "The video exchange is on. You and the operator can see each other."; +"android_chat_visitor_file_delivered_accessibility" = "Your attached file %1$s, size %2$s. \n Delivered"; +"android_chat_operator_message_accessibility" = "Operator\'s message: %1$s"; +"android_chat_operator_image_attachment_accessibility" = "Operator\'s attached image"; "android_chat_operator_name_accessibility_message" = "Operator %1$s, Message: %2$s"; -"android_chat_queue_accessibility_label" = "%1$s. \n An MSR will be with you shortly."; -"android_chat_video_accessibility_icon" = "Video icon"; -"android_chat_visitor_accessibility_image" = "Your attached image"; -"android_chat_visitor_delivered_accessibility_image" = "Your attached image. \n Delivered"; -"android_chat_visitor_accessibility_message" = "Your message: %1$s"; -"android_chat_visitor_delivered_accessibility_message" = "Your message: %1$s \n Delivered"; -"android_chat_download_complete" = "The file has been downloaded."; -"android_chat_download_failed" = "Could not download the file. Please try again."; +"android_chat_queue_message_accessibility_label" = "%1$s. \n An MSR will be with you shortly."; +"android_chat_visitor_image_attachment_accessibility" = "Your attached image"; +"android_chat_visitor_image_attachment_delivered_accessibility" = "Your attached image. \n Delivered"; +"android_chat_visitor_message_accessibility" = "Your message: %1$s"; +"android_chat_visitor_message_delivered_accessibility" = "Your message: %1$s \n Delivered"; +"android_chat_download_complete_message" = "The file has been downloaded."; "android_file_not_ready_for_preview" = "The image is not ready for preview. Please try again later."; "android_file_select_title" = "Select Picture"; -"android_file_view_error" = "Can\'t open file"; +"android_file_view_error" = "Could not open the file"; "android_notification_audio_call_channel_name" = "Call notification channel"; "android_notification_audio_call_message" = "Your microphone is now on, and the operator can hear you."; "android_notification_audio_call_title" = "Audio Call Started"; -"android_notification_end_sharing" = "End Sharing"; +"android_notification_end_screen_sharing_title" = "End Sharing"; "android_notification_one_way_video_call_message" = "The operator’s camera is on. You can now see and hear them."; -"android_notification_one_way_video_call_title" = "One-Way Video Started"; +"android_notification_one_way_video_title" = "One-Way Video Started"; "android_notification_one_way_video_no_audio" = "The operator’s camera is on. You can now see them."; "android_notification_screen_sharing_channel_name" = "Screen sharing notification channel"; "android_notification_screen_sharing_message" = "You are currently sharing your screen.\nSelect \'End Sharing\' to stop."; "android_notification_screen_sharing_title" = "Screen Sharing Started"; "android_notification_two_way_video_call_message" = "The video exchange is on. You and the operator can see and hear each other."; -"android_notification_two_way_video_call_title" = "Two-Way Video Started"; +"android_notification_two_way_video_title" = "Two-Way Video Started"; "android_notification_two_way_video_no_audio" = "The video exchange is on. You and the operator can see each other."; -"android_notifications_allow_message" = "We would like to show you notifications in the status bar. Please enable notifications in Settings."; -"android_notifications_allow_title" = "Allow Notifications?"; -"android_overlay_message" = "Allow screen overlay for the proper functioning of the app"; -"android_overlay_title" = "Screen Overlay Permissions Required"; +"android_notification_allow_notifications_message" = "We would like to show you notifications in the status bar. Please enable notifications in Settings."; +"android_notification_allow_notifications_title" = "Allow Notifications?"; +"android_overlay_permission_message" = "Allow screen overlay for the proper functioning of the app"; +"android_overlay_permission_title" = "Screen Overlay Permissions Required"; "android_permissions_message" = "Please make sure all required permissions are enabled."; "android_permissions_title" = "Additional Permissions Required"; -"android_preview_accessibility_image" = "Preview content"; -"android_preview_error_fetch" = "Could not fetch the image. Please try again."; -"android_preview_failed_message" = "Could not load the image preview. Please try again."; +"android_image_preview_accessibility" = "Preview content"; +"android_image_preview_fetch_error" = "Could not fetch the image. Please try again."; +"android_preview_failed" = "Could not load the image preview. Please try again."; "android_preview_menu_save" = "Save"; "android_preview_menu_share" = "Share"; -"android_preview_save_error_message" = "Could not save the image."; -"android_preview_save_success_message" = "The image was saved successfully."; -"android_preview_share_error_message" = "Could not share the image. Please try again."; +"android_preview_save_error" = "Could not save the image."; +"android_preview_save_success" = "The image was saved successfully."; +"android_preview_share_error" = "Could not share the image. Please try again."; "android_preview_share_title" = "Share Image"; "android_preview_title" = "Preview"; -"android_screen_sharing_accessibility_icon" = "Screen sharing icon"; -"android_screen_sharing_offer_with_notifications_message" = "The operator has requested to share your screen. To do this, you need to turn on app\'s notifications. Do this now?"; +"android_screen_sharing_offer_with_notifications_message" = "The operator has asked you to share your screen. To allow this action, please turn on notifications for this app."; "android_screen_sharing_offer_with_notifications_title" = "Start Screen Sharing?"; -"android_survey_error_network" = "The survey could not be submitted due to a network error. Please try again."; -"android_upload_error_engagement_missing" = "Engagement missing"; +"android_survey_error_network" = "The survey could not be submitted due to a network issue. Please try again."; +"android_upload_error_engagement_missing" = "Could not upload the file."; "android_upload_error_file_limit" = "Cannot upload more than 25 files"; "android_upload_error_forbidden" = "File uploading disabled"; "android_upload_error_invalid_input" = "Invalid input"; -"android_upload_error_network" = "Network timed out."; -"android_upload_error_permissions" = "File read access permission denied"; +"android_upload_error_network" = "Connection timed out."; +"android_upload_error_permissions" = "You need permission to perform this action."; "android_upload_menu_take_photo" = "Take photo"; "android_visitor_code_accessibility" = "Your visitor code is %1$s"; "android_visitor_code_loading" = "Loading your visitor code"; -"android_visitor_code_refresh" = "Refresh"; -"call.bubble.accessibility.hint" = "Deactivates minimize."; -"call.bubble.accessibility.label" = "Operator Avatar"; -"call.button.mute" = "Mute"; -"call.button.speaker" = "Speaker"; -"call.button.unmute" = "Unmute"; +"call.bubble.accessibility.hint" = "Expands call view."; +"call.bubble.accessibility.label" = "Go back to the engagement."; +"call.mute.button" = "Mute"; +"call.speaker.button" = "Speaker"; +"call.unmute.button" = "Unmute"; "call.buttons.chat.badge_value.multiple_items.accessibility.label" = "{badgeValue} unread messages"; "call.buttons.chat.badge_value.single_item.accessibility.label" = "{badgeValue} unread message"; "call.connect.first_text.accessibility.hint" = "Displays operator name."; "call.connect.second_text.accessibility.hint" = "Displays call duration."; -"call.header.back.button.accessibility.hint" = "Activates minimize."; -"call.onHold.bottom_text" = "You can continue browsing while you are on hold"; -"call.on_hold" = "On Hold"; -"call.operator.avatar.accessibility.hint" = "Displays operator avatar or placeholder."; -"call.operator.avatar.accessibility.label" = "Operator Avatar"; -"call.operator_name.accessibility.hint" = "Displays operator name."; -"call.video.operator.accessibility.label" = "Operator's Video"; -"call.video.visitor.accessibility.label" = "Your Video"; +"call.header.back.button.accessibility.hint" = "Minimizes call view."; +"call.on_hold.bottom_text" = "You can continue browsing while you are on hold"; +"call.on_hold.icon" = "On Hold"; +"call.operator_avatar.accessibility.hint" = "Shows operator picture."; +"call.operator_avatar.accessibility.label" = "Operator Picture"; +"call.operator_name.accessibility.hint" = "Shows operator name."; +"call.operator_video.accessibility.label" = "Operator's Video"; +"call.visitor_video.accessibility.label" = "Your Video"; "call_visualizer.screen_sharing.message" = "Your Screen is Being Shared"; -"call_visualizer.screen_sharing.title" = "Screen Sharing"; -"call_visualizer.visitor_code.action.close" = "Close"; -"call_visualizer.visitor_code.action.refresh" = "Refresh"; -"call_visualizer.visitor_code.close.accessibility.hint" = "Closes visitor code"; -"call_visualizer.visitor_code.close.accessibility.label" = "Close Button"; -"call_visualizer.visitor_code.refresh.accessibility.hint" = "Generates new visitor code"; +"call_visualizer.screen_sharing.header.title" = "Screen Sharing"; +"call_visualizer.visitor_code.close.accessibility.hint" = "Closes the visitor code"; +"call_visualizer.visitor_code.refresh.accessibility.hint" = "Generates a new visitor code"; "call_visualizer.visitor_code.refresh.accessibility.label" = "Refresh Button"; "call_visualizer.visitor_code.title" = "Your Visitor Code"; -"call_visualizer.visitor_code.title.accessibility.hint" = "Your five-digit visitor code is"; -"chat.duration.accessibility.label" = "Displays call duration."; +"call_visualizer.visitor_code.title.accessibility.hint" = "Shows the five-digit visitor code."; +"call.duration.accessibility.label" = "Call duration."; "chat.attach_files" = "Pick attachment"; "chat.attachment.photo_library" = "Photo Library"; "chat.attachment.take_photo" = "Take Photo or Video"; -"chat.attachment.upload.unsupported_file" = "Invalid file type!"; +"chat.attachment.unsupported_file" = "This file type is not supported."; "chat.attachment.message.accessibility.label" = "Attachment from {fileSender}"; "chat.download.downloading" = "Downloading file…"; -"chat.download.download" = "Download"; -"chat.download.failed" = "Download failed"; -"chat.file.infected_error" = "Failed to confirm the safety of the file."; -"chat.file.too_large_error" = "File size over 25MB limit!"; -"chat.file.upload.failed" = "Uploading failed"; +"chat.download.failed" = "Could not download the file."; +"chat.file.infected_file.error" = "The safety of the file could not be confirmed."; +"chat.file.size_limit.error" = "File size must be less than 25 MB."; +"chat.file.upload.failed" = "Could not upload the file."; // TODO: - Need to investigate +"chat.file.upload.generic_error" = "Could not upload the file."; // TODO: - Need to investigate "chat.file.upload.in_progress" = "Uploading file…"; -"chat.file.upload.scanning" = "Checking safety of the file…"; +"chat.file.upload.scanning" = "Checking file security…"; "chat.file.upload.success" = "Ready to send"; -"chat.file.upload.network_error" = "Network error."; -"chat.file.upload.generic_error" = "Failed to upload."; +"chat.file.upload.network_error" = "Could not upload the file due to a network issue."; "chat.input.placeholder" = "Enter Message"; -"chat.input.send" = "Send"; "chat.message.unread.accessibility.label" = "Unread messages"; "chat.message.start_engagement_placeholder" = "Send a message to start chatting"; -"chat.message.choice_card_placeholder" = "Tap on the answer above"; -"chat.operator.avatar.accessibility.label" = "Avatar"; -"chat.operator.name.accessibility.label" = "Displays operator name."; -"chat.operator_joined" = "{operatorName} has joined the conversation."; -"chat.status.delivered" = "Delivered"; -"chat.status.typing" = "Operator typing"; +"chat.choice_card.placeholder_message" = "Tap on the answer above"; +"chat.operator_avatar.accessibility.label" = "Operator Picture"; +"chat.operator_name.accessibility.label" = "Operator Name"; +"chat.operator_joined.system_message" = "{operatorName} has joined the conversation."; +"chat.message.delivered" = "Delivered"; +"chat.status.typing" = "Operator is typing"; "chat.status.typing.accessibility.label" = "{operatorName} is typing"; "chat.unread_message_divider" = "New Messages"; -"chat.upgrade.audio.text" = "Upgraded to Audio Call"; -"chat.upgrade.video.text" = "Upgraded to Video Call"; -"chat.upload.remove.accessibility.label" = "Remove upload"; +"chat.media_upgrade.audio.system_message" = "Upgraded to Audio"; +"chat.media_upgrade.video.system_message" = "Upgraded to Video"; +"chat.file.remove_upload.accessibility.label" = "Remove upload"; "chat.choice_card.button.disabled.accessibility.label" = "Disabled"; "chat.choice_card.image.accessibility.label" = "Choice card"; -"engagement.connect.placeholder" = "We are here to help!"; -"engagement.connect.with" = "Connecting with {operatorName}"; -"engagement.default_operator_name" = "Operator"; +"engagement.connection_screen.message" = "We are here to help!"; +"engagement.connection_screen.connect_with" = "Connecting with {operatorName}"; +"engagement.default_operator" = "Operator"; "engagement.end.confirmation.header" = "End Engagement?"; -"engagement.end.message" = "Are you sure you want to end engagement?"; +"engagement.end.message" = "Are you sure you want to end this engagement?"; "engagement.ended.header" = "Engagement Ended"; "engagement.ended.message" = "This engagement has ended.\nThank you!"; "engagement.media_upgrade.audio.info" = "Speak through your device"; -"engagement.media_upgrade.phone.info" = "Enter your number and we'll call you"; -"engagement.alert.microphone.header" = "Unable to access microphone"; -"ios.engagement.alert.microphone.message" = "Allow access to your microphone from device menu: “Settings” - “Privacy” - “Microphone”"; -"engagement.alert.camera.header" = "Unable to access camera"; -"ios.engagement.alert.camera.message" = "Allow access to your camera from device menu: “Settings” - “Privacy” - “Camera”"; -"engagement.alert.media_source.header" = "Unable to access media source"; -"ios.engagement.alert.media_source.message" = "This media source is not available on your device"; -"engagement.alert.screen_sharing.start.header" = "{operatorName} has asked you to share your screen"; -"engagement.alert.screen_sharing.start.message" = "{operatorName} would like to see the screen of your device"; -"engagement.alert.screen_sharing.stop.header" = "Stop screen sharing?"; -"engagement.alert.screen_sharing.stop.message" = "Are you sure you want to stop sharing your screen?"; -"engagement.minimize_video_button" = "Minimize"; -"engagement.offer_upgrade" = "{operatorName} has offered you to upgrade"; -"engagement.queue_closed.header" = "We're sorry"; -"engagement.queue_closed.message" = "Operators are no longer available. \nPlease try again later."; -"engagement.queue_leave.header" = "Are you sure you want to leave?"; -"engagement.queue_leave.message" = "You will lose your place in the queue."; -"engagement.queue_reconnection_failed.try_again" = "Please try again later."; -"engagement.queue_transferring.message" = "Transferring"; -"ios.engagement.queue_wait.video_notice" = "(By default your video will be off)"; +"engagement.media_upgrade.phone.info" = "Enter your number and will call you back."; +"alert.microphone_access.error" = "Unable to access microphone"; +"ios.alert.microphone_access.message" = "Allow access to your microphone in 'Settings' - 'Privacy & Security' - 'Microphone'"; +"alert.camera_access.error" = "Unable to access camera"; +"ios.alert.camera_access.message" = "Allow access to your camera in 'Settings' - 'Privacy & Security' - 'Camera'"; +"alert.media_source_access.error" = "Unable to access media source"; +"ios.alert.media_source.message" = "This media source is not available on your device"; +"alert.screen_sharing.start.header" = "Start Screen Sharing"; +"alert.screen_sharing.start.message" = "{operatorName} has asked you to share your screen."; +"alert.screen_sharing.stop.header" = "Stop Screen Sharing?"; +"alert.screen_sharing.stop.message" = "Are you sure you want to stop sharing your screen?"; +"engagement.minimize_video.button" = "Minimize"; +"engagement.media_upgrade.offer" = "{operatorName} has offered you to upgrade."; +"engagement.queue.closed.header" = "We are sorry! The queue is closed."; +"engagement.queue.closed.message" = "Operators are no longer available. \nPlease try again later."; +"engagement.queue.leave.header" = "Are you sure you want to leave?"; +"engagement.queue.leave.message" = "You will lose your place in the queue."; +"engagement.queue.reconnection.failed" = "Please try again later."; +"engagement.queue.transferring" = "Transferring"; +"ios.engagement.connection_screen.video_notice" = "(By default, your video will be turned off)"; "engagement.queue_wait.message" = "You can continue browsing and we will connect you automatically."; "engagement.secure_messaging.title" = "Messaging"; -"error.general" = "Something went wrong"; -"error.internal" = "Internal error"; -"error.unexpected.title" = "We're sorry, there has been an unexpected error."; +"error.general" = "Something went wrong."; +"error.internal" = "Something went wrong."; +"error.unexpected" = "Something went wrong."; "general.accept" = "Accept"; "general.back" = "Back"; "general.browse" = "Browse"; "general.cancel" = "Cancel"; "general.close" = "Close"; +"general.close.accessibility" = "Close Button"; "general.comment" = "Comment"; -"general.company_name" = "CompanyName"; +"general.company_name" = "Company Name"; "general.decline" = "Decline"; "general.download" = "Download"; "general.end" = "End"; @@ -180,19 +177,22 @@ "general.no" = "No"; "general.ok" = "Ok"; "general.open" = "Open"; -"general.powered_by" = "Powered by"; +"general.powered" = "Powered by"; "general.retry" = "Retry"; "general.selected" = "Selected"; "general.submit" = "Submit"; "general.thank_you" = "Thank you!"; "general.yes" = "Yes"; "general.you" = "You"; -"gva.error_unsupported" = "This action is not currently supported on mobile."; -"media.audio.name" = "Audio"; -"media.phone.name" = "Phone"; -"media.text.name" = "Chat"; -"media.video.name" = "Video"; -"message_center.check_messages" = "Check messages"; +"general.refresh" = "Refresh"; +"general.send" = "Send"; +"general.sending" = "Sending…"; +"gva.unsupported_action.error" = "This action is not currently supported on mobile."; +"engagement.audio.title" = "Audio"; +"engagement.phone.title" = "Phone"; +"engagement.chat.title" = "Chat"; +"engagement.video.title" = "Video"; +"message_center.welcome.check_messages" = "Check messages"; "message_center.confirmation.check_messages.accessibility.hint" = "Navigates you to the chat transcript."; "message_center.confirmation.check_messages.accessibility.label" = "Check messages"; "message_center.confirmation.subtitle" = "Your message has been sent. We will get back to you within 48 hours."; @@ -200,28 +200,26 @@ "message_center.not_authenticated.message" = "We could not verify your authentication status."; "message_center.unavailable.message" = "The Message Center is currently unavailable. Please try again later."; "message_center.unavailable.title" = "Message Center Unavailable"; -"message_center.welcome.subtitle" = "Send a message and we’ll get back to you within 48 hours"; +"message_center.welcome.subtitle" = "Send a message and we will get back to you within 48 hours."; "message_center.welcome.check_messages.accessibility.hint" = "Navigates you to the chat transcript."; "message_center.welcome.file_picker.accessibility.hint" = "Opens the file picker to attach media."; "message_center.welcome.file_picker.accessibility.label" = "File picker"; -"message_center.welcome.message_length_warning" = "The message cannot exceed 10000 characters."; -"message_center.welcome.message_text_view.placeholder" = "Enter your message"; +"message_center.welcome.message_length.error" = "The message cannot exceed 10,000 characters."; +"message_center.welcome.message_input.placeholder" = "Enter your message"; "message_center.welcome.message_title" = "Your message"; "message_center.welcome.send.accessibility.hint" = "Sends a secure message."; "message_center.welcome.title" = "Welcome to Message Center"; "screen_sharing.visitor_screen.disclaimer.title" = "You are about to share your screen"; -"screen_sharing.visitor_screen.end" = "End Screen Sharing"; +"screen_sharing.visitor_screen.end.title" = "End Screen Sharing"; "screen_sharing.visitor_screen.end.accessibility.hint" = "Ends screen sharing"; -"screensharing.visitor_screen.disclaimer.info" = "Depending on your selection, your entire screen might be shared with the operator, not just the application window."; -"send_message.send" = "Send message"; -"send_message.sending" = "Sending…"; +"screen_sharing.visitor_screen.disclaimer.info" = "Depending on your selection, your entire screen might be shared with the operator, not just the application window."; "survey.action.validation_error" = "Please provide an answer."; "survey.question.option_button.selected.accessibility.label" = "Selected: {buttonTitle}"; "survey.question.option_button.unselected.accessibility.label" = "Unselected: {buttonTitle}"; -"survey.question.text_field.accessibility.hint" = "Enter the answer"; -"survey.question.title.accessibility.label" = "Required"; -"survey.validation.title.accessibility.label" = "Please provide an answer for question above"; -"upgrade.audio.title" = "{operatorName} has offered you to upgrade to audio"; -"upgrade.video.one_way.title" = "{operatorName} has offered you to see their video"; -"upgrade.video.two_way.title" = "{operatorName} has offered you to upgrade to video"; +"survey.question.input.accessibility.hint" = "Enter the answer"; +"survey.question.required.accessibility.label" = "This is a required question."; +"survey.validation.title.accessibility.label" = "Please provide an answer for the question above."; +"media_upgrade.audio.title" = "{operatorName} has offered you to upgrade to audio"; +"media_upgrade.video.one_way.title" = "{operatorName} has offered you to see their video"; +"media_upgrade.video.two_way.title" = "{operatorName} has offered you to upgrade to video"; "visitor_code.failed" = "Could not load the visitor code. Please try refreshing."; diff --git a/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift b/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift index bb02f5b08..48b120483 100644 --- a/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift +++ b/GliaWidgets/SecureConversations/Confirmation/Theme+SecureConversationsConfirmation.swift @@ -23,7 +23,7 @@ extension Theme { ) let checkMessagesButtonStyle = SecureConversations.ConfirmationStyle.CheckMessagesButtonStyle( - title: Localization.MessageCenter.checkMessages, + title: Localization.MessageCenter.Welcome.checkMessages, font: font.bodyText, textColor: color.baseLight, backgroundColor: color.primary, diff --git a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift index 8ae9f92ab..448b677d1 100644 --- a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift +++ b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift @@ -25,13 +25,13 @@ extension Theme { ) let checkMessagesButtonStyle = SecureConversations.WelcomeStyle.CheckMessagesButtonStyle( - title: Localization.MessageCenter.checkMessages, + title: Localization.MessageCenter.Welcome.checkMessages, font: font.header2, textStyle: .title2, color: color.primary, accessibility: .init( isFontScalingEnabled: true, - label: Localization.MessageCenter.checkMessages, + label: Localization.MessageCenter.Welcome.checkMessages, hint: Localization.MessageCenter.Welcome.CheckMessages.Accessibility.hint ) ) @@ -45,7 +45,7 @@ extension Theme { ) let messageTextViewNormalStyle = SecureConversations.WelcomeStyle.MessageTextViewNormalStyle( - placeholderText: Localization.MessageCenter.Welcome.MessageTextView.placeholder, + placeholderText: Localization.MessageCenter.Welcome.MessageInput.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -59,7 +59,7 @@ extension Theme { ) let messageTextViewActiveStyle = SecureConversations.WelcomeStyle.MessageTextViewActiveStyle( - placeholderText: Localization.MessageCenter.Welcome.MessageTextView.placeholder, + placeholderText: Localization.MessageCenter.Welcome.MessageInput.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -73,7 +73,7 @@ extension Theme { ) let messageTextViewDisabledStyle = SecureConversations.WelcomeStyle.MessageTextViewDisabledStyle( - placeholderText: Localization.MessageCenter.Welcome.MessageTextView.placeholder, + placeholderText: Localization.MessageCenter.Welcome.MessageInput.placeholder, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, textFont: font.bodyText, @@ -93,7 +93,7 @@ extension Theme { ) let sendButtonEnabledStyle = SecureConversations.WelcomeStyle.SendButtonEnabledStyle( - title: Localization.Chat.Input.send, + title: Localization.General.send, font: font.bodyText, textStyle: .body, textColor: color.baseLight, @@ -103,13 +103,13 @@ extension Theme { cornerRadius: 4, accessibility: .init( isFontScalingEnabled: true, - label: Localization.Chat.Input.send, + label: Localization.General.send, hint: Localization.MessageCenter.Welcome.Send.Accessibility.hint ) ) let sendButtonDisabledStyle = SecureConversations.WelcomeStyle.SendButtonDisabledStyle( - title: Localization.Chat.Input.send, + title: Localization.General.send, font: font.bodyText, textStyle: .body, textColor: .disabledTitle, @@ -119,13 +119,13 @@ extension Theme { cornerRadius: 4, accessibility: .init( isFontScalingEnabled: true, - label: Localization.Chat.Input.send, + label: Localization.General.send, hint: Localization.MessageCenter.Welcome.Send.Accessibility.hint ) ) let sendButtonLoadingStyle = SecureConversations.WelcomeStyle.SendButtonLoadingStyle( - title: Localization.Chat.Input.send, + title: Localization.General.send, font: font.bodyText, textStyle: .body, textColor: .disabledTitle, @@ -136,7 +136,7 @@ extension Theme { cornerRadius: 4, accessibility: .init( isFontScalingEnabled: true, - label: Localization.Chat.Input.send, + label: Localization.General.send, hint: Localization.MessageCenter.Welcome.Send.Accessibility.hint ) ) @@ -152,7 +152,7 @@ extension Theme { textFont: .systemFont(ofSize: 12.0), textStyle: .caption1, iconColor: color.systemNegative, - messageLengthLimitText: Localization.MessageCenter.Welcome.messageLengthWarning, + messageLengthLimitText: Localization.MessageCenter.Welcome.MessageLength.error, accessibility: .init(isFontScalingEnabled: true) ) @@ -201,9 +201,9 @@ extension Theme { textColor: color.baseDark, infoFont: font.caption, infoColor: color.systemNegative, - infoFileTooBig: Localization.Chat.File.tooLargeError, - infoUnsupportedFileType: Localization.Chat.Attachment.Upload.unsupportedFile, - infoSafetyCheckFailed: Localization.Chat.File.infectedError, + infoFileTooBig: Localization.Chat.File.SizeLimit.error, + infoUnsupportedFileType: Localization.Chat.Attachment.unsupportedFile, + infoSafetyCheckFailed: Localization.Chat.File.InfectedFile.error, infoNetworkError: Localization.Chat.File.Upload.networkError, infoGenericError: Localization.Chat.File.Upload.genericError ) @@ -219,7 +219,7 @@ extension Theme { removeButtonColor: color.baseNormal, backgroundColor: .commonGray, accessibility: .init( - removeButtonAccessibilityLabel: Localization.Chat.Upload.Remove.Accessibility.label, + removeButtonAccessibilityLabel: Localization.Chat.File.RemoveUpload.Accessibility.label, progressPercentValue: Localization.Templates.percentValue, fileNameWithProgressValue: Localization.Templates.fileNameWithProgressValue, isFontScalingEnabled: true diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift index 039f49cc3..86fcc7a7d 100644 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift @@ -46,7 +46,7 @@ extension CallVisualizer { $0.titleLabel?.numberOfLines = 0 $0.titleLabel?.translatesAutoresizingMaskIntoConstraints = false $0.accessibilityIdentifier = "end_screen_sharing_button" - $0.accessibilityLabel = Localization.ScreenSharing.VisitorScreen.end + $0.accessibilityLabel = Localization.ScreenSharing.VisitorScreen.End.title $0.accessibilityHint = Localization.ScreenSharing.VisitorScreen.End.Accessibility.hint } private lazy var contentStackView = UIStackView.make( diff --git a/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift b/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift index a1962baf4..036c104de 100644 --- a/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift +++ b/GliaWidgets/Sources/CallVisualizer/VideoCall/ViewModel/VideoCallViewModel.swift @@ -101,7 +101,7 @@ extension CallVisualizer { videoButtonState = .active videoButtonEnabled = true minimizeButtonEnabled = true - title = Localization.Media.Video.name + title = Localization.Engagement.Video.title callDuration = "" topLabelHidden = false endScreenShareButtonHidden = environment.screenShareHandler.status().value == .stopped @@ -503,7 +503,7 @@ private extension CallVisualizer.VideoCallViewModel { default: topLabelHidden = true } - title = Localization.Media.Video.name + title = Localization.Engagement.Video.title } updateButtons() } diff --git a/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift b/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift index 3c166e4e5..afcdb5cc4 100644 --- a/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift +++ b/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift @@ -102,7 +102,7 @@ extension CallVisualizer { ).make { button in button.accessibilityIdentifier = "visitor_code_alert_close_button" button.accessibilityTraits = .button - button.accessibilityLabel = Localization.CallVisualizer.VisitorCode.Close.Accessibility.label + button.accessibilityLabel = Localization.General.Close.accessibility button.accessibilityHint = Localization.CallVisualizer.VisitorCode.Close.Accessibility.hint } diff --git a/GliaWidgets/Sources/Extensions/String+TemplateString.swift b/GliaWidgets/Sources/Extensions/String+TemplateString.swift index ea9315ffb..d4d28aeca 100644 --- a/GliaWidgets/Sources/Extensions/String+TemplateString.swift +++ b/GliaWidgets/Sources/Extensions/String+TemplateString.swift @@ -1,6 +1,6 @@ extension String { func withOperatorName(_ name: String?) -> String { - let name = name ?? Localization.Engagement.defaultOperatorName + let name = name ?? Localization.Engagement.defaultOperator return replacingOccurrences(of: "{operatorName}", with: name) } diff --git a/GliaWidgets/Sources/Theme/Theme+Alert.swift b/GliaWidgets/Sources/Theme/Theme+Alert.swift index da3d0f6eb..5f5da0a23 100644 --- a/GliaWidgets/Sources/Theme/Theme+Alert.swift +++ b/GliaWidgets/Sources/Theme/Theme+Alert.swift @@ -21,7 +21,7 @@ extension Theme { ) ) let poweredBy = PoweredByStyle( - text: Localization.General.poweredBy, + text: Localization.General.powered, font: font.caption, accessibility: .init(isFontScalingEnabled: true) ) diff --git a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift index 55249e3ae..d70056d0c 100644 --- a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift +++ b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift @@ -1,8 +1,8 @@ extension Theme { var alertConfigurationStyle: AlertConfiguration { let leaveQueue = ConfirmationAlertConfiguration( - title: Localization.Engagement.QueueLeave.header, - message: Localization.Engagement.QueueLeave.message, + title: Localization.Engagement.Queue.Leave.header, + message: Localization.Engagement.Queue.Leave.message, negativeTitle: Localization.General.no, positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, @@ -22,19 +22,19 @@ extension Theme { buttonTitle: Localization.General.ok ) let endScreenShare = ConfirmationAlertConfiguration( - title: Localization.Engagement.Alert.ScreenSharing.Stop.header, - message: Localization.Engagement.Alert.ScreenSharing.Stop.message, + title: Localization.Alert.ScreenSharing.Stop.header, + message: Localization.Alert.ScreenSharing.Stop.message, negativeTitle: Localization.General.no, positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, showsPoweredBy: showsPoweredBy ) let operatorsUnavailable = MessageAlertConfiguration( - title: Localization.Engagement.QueueClosed.header, - message: Localization.Engagement.QueueClosed.message + title: Localization.Engagement.Queue.Closed.header, + message: Localization.Engagement.Queue.Closed.message ) let audioAction = MediaUpgradeActionStyle( - title: Localization.Media.Audio.name, + title: Localization.Engagement.Audio.title, titleFont: font.header3, titleColor: color.baseDark, info: Localization.Engagement.MediaUpgrade.Audio.info, @@ -46,7 +46,7 @@ extension Theme { iconColor: color.primary ) let phoneAction = MediaUpgradeActionStyle( - title: Localization.Media.Phone.name, + title: Localization.Engagement.Phone.title, titleFont: font.header3, titleColor: color.baseDark, info: Localization.Engagement.MediaUpgrade.Phone.info, @@ -58,62 +58,62 @@ extension Theme { iconColor: color.primary ) let mediaUpgrade = MultipleMediaUpgradeAlertConfiguration( - title: Localization.Engagement.offerUpgrade, + title: Localization.Engagement.MediaUpgrade.offer, audioUpgradeAction: audioAction, phoneUpgradeAction: phoneAction, showsPoweredBy: showsPoweredBy ) let audioUpgrade = SingleMediaUpgradeAlertConfiguration( - title: Localization.Upgrade.Audio.title, + title: Localization.MediaUpgrade.Audio.title, titleImage: Asset.upgradeAudio.image, decline: Localization.General.decline, accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let oneWayVideoUpgrade = SingleMediaUpgradeAlertConfiguration( - title: Localization.Upgrade.Video.OneWay.title, + title: Localization.MediaUpgrade.Video.OneWay.title, titleImage: Asset.upgradeVideo.image, decline: Localization.General.decline, accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let twoWayVideoUpgrade = SingleMediaUpgradeAlertConfiguration( - title: Localization.Upgrade.Video.TwoWay.title, + title: Localization.MediaUpgrade.Video.TwoWay.title, titleImage: Asset.upgradeVideo.image, decline: Localization.General.decline, accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let screenShareOffer = ScreenShareOfferAlertConfiguration( - title: Localization.Engagement.Alert.ScreenSharing.Start.header, - message: Localization.Engagement.Alert.ScreenSharing.Start.message, + title: Localization.Alert.ScreenSharing.Start.header, + message: Localization.Alert.ScreenSharing.Start.message, titleImage: Asset.startScreenShare.image, decline: Localization.General.decline, accept: Localization.General.accept, showsPoweredBy: showsPoweredBy ) let microphoneSettings = SettingsAlertConfiguration( - title: Localization.Engagement.Alert.Microphone.header, - message: Localization.Ios.Engagement.Alert.Microphone.message, + title: Localization.Alert.MicrophoneAccess.error, + message: Localization.Ios.Alert.MicrophoneAccess.message, settingsTitle: Localization.Alert.Action.settings, cancelTitle: Localization.General.cancel ) let cameraSettings = SettingsAlertConfiguration( - title: Localization.Engagement.Alert.Camera.header, - message: Localization.Ios.Engagement.Alert.Camera.message, + title: Localization.Alert.CameraAccess.error, + message: Localization.Ios.Alert.CameraAccess.message, settingsTitle: Localization.Alert.Action.settings, cancelTitle: Localization.General.cancel ) let mediaSourceNotAvailable = MessageAlertConfiguration( - title: Localization.Engagement.Alert.MediaSource.header, - message: Localization.Ios.Engagement.Alert.MediaSource.message + title: Localization.Alert.MediaSourceAccess.error, + message: Localization.Ios.Alert.MediaSource.message ) let unexpected = MessageAlertConfiguration( - title: Localization.Error.Unexpected.title, - message: Localization.Engagement.QueueReconnectionFailed.tryAgain + title: Localization.Error.unexpected, + message: Localization.Engagement.Queue.Reconnection.failed ) let api = MessageAlertConfiguration( - title: Localization.Error.Unexpected.title, + title: Localization.Error.unexpected, message: Localization.Templates.errorMessage ) let unavailableMessageCenter = MessageAlertConfiguration( @@ -129,7 +129,7 @@ extension Theme { ) let unsupportedGvaBroadcastError = MessageAlertConfiguration( - title: Localization.Gva.errorUnsupported, + title: Localization.Gva.UnsupportedAction.error, message: nil ) diff --git a/GliaWidgets/Sources/Theme/Theme+Call.swift b/GliaWidgets/Sources/Theme/Theme+Call.swift index 8b07db7d2..0cfa02bef 100644 --- a/GliaWidgets/Sources/Theme/Theme+Call.swift +++ b/GliaWidgets/Sources/Theme/Theme+Call.swift @@ -63,8 +63,8 @@ extension Theme { animationColor: .lightGray, onHoldOverlay: onHoldOverlay, accessibility: .init( - label: Localization.Call.Operator.Avatar.Accessibility.label, - hint: Localization.Call.Operator.Avatar.Accessibility.hint + label: Localization.Call.OperatorAvatar.Accessibility.label, + hint: Localization.Call.OperatorAvatar.Accessibility.hint ) ) let queue = ConnectStatusStyle( @@ -72,7 +72,7 @@ extension Theme { firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: Localization.Engagement.Connect.placeholder, + secondText: Localization.Engagement.ConnectionScreen.message, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, @@ -83,7 +83,7 @@ extension Theme { ) ) let connecting = ConnectStatusStyle( - firstText: Localization.Engagement.Connect.with, + firstText: Localization.Engagement.ConnectionScreen.connectWith, firstTextFont: font.header2, firstTextFontColor: color.baseLight, firstTextStyle: .title2, @@ -128,7 +128,7 @@ extension Theme { ) ) let transferring = ConnectStatusStyle( - firstText: Localization.Engagement.QueueTransferring.message, + firstText: Localization.Engagement.Queue.transferring, firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, @@ -146,7 +146,7 @@ extension Theme { onHold: onHold ) let onHoldStyle = CallStyle.OnHoldStyle( - onHoldText: Localization.Call.onHold, + onHoldText: Localization.Call.OnHold.icon, descriptionText: Localization.Call.OnHold.bottomText, localVideoStreamLabelText: Localization.General.you, localVideoStreamLabelFont: font.mediumSubtitle2, @@ -158,14 +158,14 @@ extension Theme { connect: connect, backgroundColor: .fill(color: .white), preferredStatusBarStyle: .lightContent, - audioTitle: Localization.Media.Audio.name, - videoTitle: Localization.Media.Video.name, + audioTitle: Localization.Engagement.Audio.title, + videoTitle: Localization.Engagement.Video.title, operatorName: Localization.Templates.operatorName, operatorNameFont: font.header1, operatorNameColor: color.baseLight, durationFont: font.bodyText, durationColor: color.baseLight, - topText: Localization.Ios.Engagement.QueueWait.videoNotice, + topText: Localization.Ios.Engagement.ConnectionScreen.videoNotice, topTextFont: font.subtitle, topTextColor: color.baseLight, bottomText: Localization.Engagement.QueueWait.message, @@ -176,8 +176,8 @@ extension Theme { accessibility: .init( operatorNameHint: Localization.Call.Connect.FirstText.Accessibility.hint, durationHint: Localization.Call.Connect.SecondText.Accessibility.hint, - localVideoLabel: Localization.Call.Video.Visitor.Accessibility.label, - remoteVideoLabel: Localization.Call.Video.Operator.Accessibility.label, + localVideoLabel: Localization.Call.VisitorVideo.Accessibility.label, + remoteVideoLabel: Localization.Call.OperatorVideo.Accessibility.label, isFontScalingEnabled: true ) ) @@ -198,7 +198,7 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callChat.image, imageColor: activeImageColor, - title: Localization.Media.Text.name, + title: Localization.Engagement.Chat.title, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, @@ -210,7 +210,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callChat.image, imageColor: inactiveImageColor, - title: Localization.Media.Text.name, + title: Localization.Engagement.Chat.title, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -220,7 +220,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callChat.image, imageColor: inactiveImageColor, - title: Localization.Media.Text.name, + title: Localization.Engagement.Chat.title, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -238,7 +238,7 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callVideoActive.image, imageColor: activeImageColor, - title: Localization.Media.Video.name, + title: Localization.Engagement.Video.title, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, @@ -250,7 +250,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callVideoInactive.image, imageColor: inactiveImageColor, - title: Localization.Media.Video.name, + title: Localization.Engagement.Video.title, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -260,7 +260,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callVideoInactive.image, imageColor: inactiveImageColor, - title: Localization.Media.Video.name, + title: Localization.Engagement.Video.title, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -273,12 +273,13 @@ extension Theme { isFontScalingEnabled: true ) ) +#warning("check Localization.Call.Unmute.button") let muteButton = CallButtonStyle( active: CallButtonStyle.StateStyle( backgroundColor: activeBackgroundColor, image: Asset.callMuteActive.image, imageColor: activeImageColor, - title: Localization.Call.Button.unmute, + title: Localization.Call.Unmute.button, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, @@ -290,7 +291,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callMuteInactive.image, imageColor: inactiveImageColor, - title: Localization.Call.Button.mute, + title: Localization.Call.Mute.button, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -300,7 +301,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callMuteInactive.image, imageColor: inactiveImageColor, - title: Localization.Call.Button.mute, + title: Localization.Call.Mute.button, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -318,7 +319,7 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callSpeakerActive.image, imageColor: activeImageColor, - title: Localization.Call.Button.speaker, + title: Localization.Call.Speaker.button, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, @@ -330,7 +331,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callSpeakerInactive.image, imageColor: inactiveImageColor, - title: Localization.Call.Button.speaker, + title: Localization.Call.Speaker.button, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -340,7 +341,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callSpeakerInactive.image, imageColor: inactiveImageColor, - title: Localization.Call.Button.speaker, + title: Localization.Call.Speaker.button, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -358,7 +359,7 @@ extension Theme { backgroundColor: activeBackgroundColor, image: Asset.callMiminize.image, imageColor: activeImageColor, - title: Localization.Engagement.minimizeVideoButton, + title: Localization.Engagement.MinimizeVideo.button, titleFont: activeTitleFont, titleColor: activeTitleColor, textStyle: .caption1, @@ -370,7 +371,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callMiminize.image, imageColor: inactiveImageColor, - title: Localization.Engagement.minimizeVideoButton, + title: Localization.Engagement.MinimizeVideo.button, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, @@ -380,7 +381,7 @@ extension Theme { backgroundColor: inactiveBackgroundColor, image: Asset.callMiminize.image, imageColor: inactiveImageColor, - title: Localization.Engagement.minimizeVideoButton, + title: Localization.Engagement.MinimizeVideo.button, titleFont: inactiveTitleFont, titleColor: inactiveTitleColor, textStyle: .caption1, diff --git a/GliaWidgets/Sources/Theme/Theme+Chat.swift b/GliaWidgets/Sources/Theme/Theme+Chat.swift index 7f3d75f86..a14f32063 100644 --- a/GliaWidgets/Sources/Theme/Theme+Chat.swift +++ b/GliaWidgets/Sources/Theme/Theme+Chat.swift @@ -35,7 +35,7 @@ extension Theme { image: Asset.startScreenShare.image, color: color.baseLight, accessibility: .init( - label: Localization.ScreenSharing.VisitorScreen.end, + label: Localization.ScreenSharing.VisitorScreen.End.title, hint: "" ) ) @@ -65,8 +65,8 @@ extension Theme { animationColor: color.primary, onHoldOverlay: onHoldOverlay, accessibility: .init( - label: Localization.Chat.Operator.Avatar.Accessibility.label, - hint: Localization.Call.Operator.Avatar.Accessibility.hint + label: Localization.Chat.OperatorAvatar.Accessibility.label, + hint: Localization.Call.OperatorAvatar.Accessibility.hint ) ) let queue = ConnectStatusStyle( @@ -74,18 +74,18 @@ extension Theme { firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, - secondText: Localization.Engagement.Connect.placeholder, + secondText: Localization.Engagement.ConnectionScreen.message, secondTextFont: font.subtitle, secondTextFontColor: color.baseNormal, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, + firstTextHint: Localization.Chat.OperatorName.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) ) let connecting = ConnectStatusStyle( - firstText: Localization.Engagement.Connect.with, + firstText: Localization.Engagement.ConnectionScreen.connectWith, firstTextFont: font.header2, firstTextFontColor: color.baseDark, firstTextStyle: .title2, @@ -94,7 +94,7 @@ extension Theme { secondTextFontColor: color.baseDark, secondTextStyle: .title2, accessibility: .init( - firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, + firstTextHint: Localization.Chat.OperatorName.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) @@ -104,12 +104,12 @@ extension Theme { firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, - secondText: Localization.Chat.operatorJoined, + secondText: Localization.Chat.OperatorJoined.systemMessage, secondTextFont: font.subtitle, secondTextFontColor: color.primary, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, + firstTextHint: Localization.Chat.OperatorName.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) @@ -119,18 +119,18 @@ extension Theme { firstTextFont: font.header1, firstTextFontColor: color.baseLight, firstTextStyle: .title1, - secondText: Localization.Chat.operatorJoined, + secondText: Localization.Chat.OperatorJoined.systemMessage, secondTextFont: font.subtitle, secondTextFontColor: color.baseLight, secondTextStyle: .footnote, accessibility: .init( - firstTextHint: Localization.Chat.Operator.Name.Accessibility.label, + firstTextHint: Localization.Chat.OperatorName.Accessibility.label, secondTextHint: nil, isFontScalingEnabled: true ) ) let transferring = ConnectStatusStyle( - firstText: Localization.Engagement.QueueTransferring.message, + firstText: Localization.Engagement.Queue.transferring, firstTextFont: font.header1, firstTextFontColor: color.baseDark, firstTextStyle: .title1, @@ -176,7 +176,7 @@ extension Theme { textStyle: .caption1, accessibility: .init(isFontScalingEnabled: true) ), - delivered: Localization.Chat.Status.delivered, + delivered: Localization.Chat.Message.delivered, accessibility: .init(isFontScalingEnabled: true) ) let operatorImageFile = ChatImageFileContentStyle( @@ -294,14 +294,14 @@ extension Theme { let sendButton = MessageButtonStyle( image: Asset.chatSend.image, color: color.primary, - accessibility: .init(accessibilityLabel: Localization.Chat.Input.send) + accessibility: .init(accessibilityLabel: Localization.General.send) ) let messageEntry = ChatMessageEntryStyle( messageFont: font.bodyText, messageColor: color.baseDark, enterMessagePlaceholder: Localization.Chat.Input.placeholder, startEngagementPlaceholder: Localization.Chat.Message.startEngagementPlaceholder, - choiceCardPlaceholder: Localization.Chat.Message.choiceCardPlaceholder, + choiceCardPlaceholder: Localization.Chat.ChoiceCard.placeholderMessage, placeholderFont: font.bodyText, placeholderColor: color.baseNormal, separatorColor: color.baseShade, @@ -317,28 +317,28 @@ extension Theme { let audioUpgrade = ChatCallUpgradeStyle( icon: Asset.upgradeAudio.image, iconColor: color.primary, - text: Localization.Chat.Upgrade.Audio.text, + text: Localization.Chat.MediaUpgrade.Audio.systemMessage, textFont: font.bodyText, textColor: color.baseDark, durationFont: font.bodyText, durationColor: color.baseNormal, borderColor: color.baseShade, accessibility: .init( - durationTextHint: Localization.Chat.Duration.Accessibility.label, + durationTextHint: Localization.Call.Duration.Accessibility.label, isFontScalingEnabled: true ) ) let videoUpgrade = ChatCallUpgradeStyle( icon: Asset.upgradeVideo.image, iconColor: color.primary, - text: Localization.Chat.Upgrade.Video.text, + text: Localization.Chat.MediaUpgrade.Video.systemMessage, textFont: font.bodyText, textColor: color.baseDark, durationFont: font.bodyText, durationColor: color.baseNormal, borderColor: color.baseShade, accessibility: .init( - durationTextHint: Localization.Chat.Duration.Accessibility.label, + durationTextHint: Localization.Call.Duration.Accessibility.label, isFontScalingEnabled: true ) ) @@ -352,7 +352,7 @@ extension Theme { let callBubble = BubbleStyle( userImage: userImage, accessibility: .init( - label: Localization.Call.Operator.Avatar.Accessibility.label, + label: Localization.Call.OperatorAvatar.Accessibility.label, hint: Localization.Call.Bubble.Accessibility.hint ) ) @@ -393,7 +393,7 @@ extension Theme { connect: connect, backgroundColor: .fill(color: color.background), preferredStatusBarStyle: .lightContent, - title: Localization.Media.Text.name, + title: Localization.Engagement.Chat.title, visitorMessageStyle: visitorMessage, operatorMessageStyle: operatorMessage, choiceCardStyle: choiceCard, @@ -405,7 +405,7 @@ extension Theme { unreadMessageIndicator: unreadMessageIndicator, operatorTypingIndicator: operatorTypingIndicator, accessibility: .init( - operator: Localization.Engagement.defaultOperatorName, + operator: Localization.Engagement.defaultOperator, visitor: Localization.General.you, isFontScalingEnabled: true ), @@ -447,9 +447,9 @@ extension Theme { textColor: color.baseDark, infoFont: font.caption, infoColor: color.systemNegative, - infoFileTooBig: Localization.Chat.File.tooLargeError, - infoUnsupportedFileType: Localization.Chat.Attachment.Upload.unsupportedFile, - infoSafetyCheckFailed: Localization.Chat.File.infectedError, + infoFileTooBig: Localization.Chat.File.SizeLimit.error, + infoUnsupportedFileType: Localization.Chat.Attachment.unsupportedFile, + infoSafetyCheckFailed: Localization.Chat.File.InfectedFile.error, infoNetworkError: Localization.Chat.File.Upload.networkError, infoGenericError: Localization.Chat.File.Upload.genericError ) @@ -464,7 +464,7 @@ extension Theme { removeButtonImage: Asset.uploadRemove.image, removeButtonColor: color.baseNormal, accessibility: .init( - removeButtonAccessibilityLabel: Localization.Chat.Upload.Remove.Accessibility.label, + removeButtonAccessibilityLabel: Localization.Chat.File.RemoveUpload.Accessibility.label, progressPercentValue: Localization.Templates.percentValue, fileNameWithProgressValue: Localization.Templates.fileNameWithProgressValue, isFontScalingEnabled: true @@ -485,7 +485,7 @@ extension Theme { accessibility: .init(isFontScalingEnabled: true) ) let download = ChatFileDownloadStateStyle( - text: Localization.Chat.Download.download, + text: Localization.General.download, font: font.mediumSubtitle2, textColor: color.baseDark, infoFont: font.caption, diff --git a/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift b/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift index f84e90f4d..dcd45dce0 100644 --- a/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift +++ b/GliaWidgets/Sources/Theme/Theme+ScreenSharing.swift @@ -3,19 +3,19 @@ import UIKit extension Theme { var screenSharingStyle: ScreenSharingViewStyle { return ScreenSharingViewStyle( - title: Localization.CallVisualizer.ScreenSharing.title, + title: Localization.CallVisualizer.ScreenSharing.Header.title, header: chat.header, messageText: Localization.CallVisualizer.ScreenSharing.message, messageTextFont: font.header2, messageTextColor: color.baseDark, buttonStyle: .init( - title: Localization.ScreenSharing.VisitorScreen.end, + title: Localization.ScreenSharing.VisitorScreen.End.title, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.systemNegative), cornerRaidus: 4, accessibility: .init( - label: Localization.ScreenSharing.VisitorScreen.end, + label: Localization.ScreenSharing.VisitorScreen.End.title, isFontScalingEnabled: true ) ), diff --git a/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift b/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift index 11d3f6667..a07dcbc8a 100644 --- a/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift +++ b/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift @@ -13,14 +13,14 @@ extension Theme { ) let actionButton = ActionButtonStyle( - title: Localization.CallVisualizer.VisitorCode.Action.refresh, + title: Localization.General.refresh, titleFont: font.buttonLabel, titleColor: color.baseLight, backgroundColor: .fill(color: color.primary) ) let poweredBy = PoweredByStyle( - text: Localization.General.poweredBy, + text: Localization.General.powered, font: font.caption, accessibility: .init(isFontScalingEnabled: true) ) diff --git a/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift b/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift index b29e5239e..eeb986ba3 100644 --- a/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift +++ b/GliaWidgets/Sources/ViewController/Survey/Survey.ViewController.Props.swift @@ -123,7 +123,7 @@ extension Survey.ViewController.Props { ) -> Survey.ScaleQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? Localization.Survey.Question.Title.Accessibility.label + ? Localization.Survey.Question.Required.Accessibility.label : nil var scaleProps = Survey.ScaleQuestionView.Props( @@ -163,7 +163,7 @@ extension Survey.ViewController.Props { ) -> Survey.BooleanQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? Localization.Survey.Question.Title.Accessibility.label + ? Localization.Survey.Question.Required.Accessibility.label : nil var booleanProps = Survey.BooleanQuestionView.Props( @@ -200,7 +200,7 @@ extension Survey.ViewController.Props { ) -> Survey.SingleChoiceQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? Localization.Survey.Question.Title.Accessibility.label + ? Localization.Survey.Question.Required.Accessibility.label : nil var scaleProps = Survey.SingleChoiceQuestionView.Props( @@ -241,7 +241,7 @@ extension Survey.ViewController.Props { ) -> Survey.InputQuestionView.Props { let accessibilityValue = sdkQuestion.required - ? Localization.Survey.Question.Title.Accessibility.label + ? Localization.Survey.Question.Required.Accessibility.label : nil var inputProps = Survey.InputQuestionView.Props( @@ -250,7 +250,7 @@ extension Survey.ViewController.Props { isRequired: sdkQuestion.required, accessibility: .init( titleValue: accessibilityValue, - fieldHint: Localization.Survey.Question.TextField.Accessibility.hint + fieldHint: Localization.Survey.Question.Input.Accessibility.hint ) ) inputProps.textDidChange = { newValue in diff --git a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift index 9076368fd..ec2f08e4d 100644 --- a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift @@ -93,7 +93,7 @@ class CallViewModel: EngagementViewModel, ViewModel { action?(.queue) case .engaged: showConnecting() - let operatorName = interactor.engagedOperator?.firstName ?? Localization.Engagement.defaultOperatorName + let operatorName = interactor.engagedOperator?.firstName ?? Localization.Engagement.defaultOperator action?(.setOperatorName(operatorName)) case .ended: call.end() @@ -133,7 +133,7 @@ class CallViewModel: EngagementViewModel, ViewModel { private func update(for callKind: CallKind) { switch callKind { case .audio: - action?(.setTitle(Localization.Media.Audio.name)) + action?(.setTitle(Localization.Engagement.Audio.title)) action?(.setTopTextHidden(true)) case .video(let direction): switch direction { @@ -144,7 +144,7 @@ class CallViewModel: EngagementViewModel, ViewModel { action?(.setTopTextHidden(true)) } - action?(.setTitle(Localization.Media.Video.name)) + action?(.setTitle(Localization.Engagement.Video.title)) } updateButtons() } diff --git a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift index 2f660e71a..d9119690a 100644 --- a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/CallButtonBarStyle.Mock.swift @@ -43,7 +43,7 @@ extension CallButtonStyle.StateStyle { backgroundColor: ColorType = .fill(color: UIColor.white.withAlphaComponent(0.9)), image: UIImage = Asset.callChat.image, imageColor: ColorType = .fill(color: Color.baseDark), - title: String = Localization.Media.Text.name, + title: String = Localization.Engagement.Chat.title, titleFont: UIFont = .systemFont(ofSize: 12, weight: .regular), titleColor: UIColor = Color.baseLight, textStyle: UIFont.TextStyle = .caption1, @@ -67,7 +67,7 @@ extension CallButtonStyle.StateStyle { backgroundColor: ColorType = .fill(color: UIColor.black.withAlphaComponent(0.4)), image: UIImage = Asset.callChat.image, imageColor: ColorType = .fill(color: Color.baseLight), - title: String = Localization.Media.Text.name, + title: String = Localization.Engagement.Chat.title, titleFont: UIFont = .systemFont(ofSize: 12, weight: .regular), titleColor: UIColor = Color.baseLight, textStyle: UIFont.TextStyle = .caption1, @@ -89,7 +89,7 @@ extension CallButtonStyle.StateStyle { backgroundColor: ColorType = .fill(color: UIColor.black.withAlphaComponent(0.4)), image: UIImage = Asset.callChat.image, imageColor: ColorType = .fill(color: Color.baseLight), - title: String = Localization.Media.Text.name, + title: String = Localization.Engagement.Chat.title, titleFont: UIFont = .systemFont(ofSize: 12, weight: .regular), titleColor: UIColor = Color.baseLight, textStyle: UIFont.TextStyle = .caption1, diff --git a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift index 17704b310..62e17e3ec 100644 --- a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift @@ -36,7 +36,7 @@ extension HeaderButtonStyle { extension ActionButtonStyle { static func mock( - title: String = Localization.ScreenSharing.VisitorScreen.end, + title: String = Localization.ScreenSharing.VisitorScreen.End.title, titleFont: UIFont = .systemFont(ofSize: 16, weight: .regular), titleColor: UIColor = .white, backgroundColor: ColorType = .fill(color: Color.systemNegative), diff --git a/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift b/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift index e8a897498..573aa7e1b 100644 --- a/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift +++ b/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift @@ -171,7 +171,7 @@ extension GliaTests { try sdk.startEngagement(engagementKind: .chat, in: ["queueId"]) let configuredSdkTheme = resultingViewFactory?.theme - XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "CompanyName") - XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "CompanyName") + XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Company Name") + XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "Company Name") } } From 38e361530d6d554aba00f035b2967ddf8c453d19 Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Tue, 26 Sep 2023 15:32:35 +0300 Subject: [PATCH 22/40] Convert ScreenSharingView to SwiftUI This PR converts ScreenSharingView to SwiftUI MOB-2720 --- GliaWidgets.xcodeproj/project.pbxproj | 62 ++++--- GliaWidgets/Public/Glia/Glia.swift | 3 +- ...SecureConversations.ConfirmationView.swift | 8 +- ...ersations.ConfirmationViewController.swift | 9 +- .../CallVisualizer+Environment.swift | 1 + .../CallVisualizer/CallVisualizer.swift | 3 +- ...llVisualizer.Coordinator.Environment.swift | 1 + .../CallVisualizer.Coordinator.swift | 3 +- .../CallVisualizer.Environment.Mock.swift | 3 +- .../Mock/ScreenSharingViewModel.mock.swift | 19 ++ ...ScreenSharingCoordinator+Environment.swift | 1 + .../ScreenSharingCoordinator.swift | 35 ++-- .../Model/ScreenSharingViewModel.swift | 110 ++++++++++++ ...ScreenSharingViewStyle.Accessibility.swift | 0 .../{ => Style}/ScreenSharingViewStyle.swift | 0 .../View/ScreenSharingView.swift | 166 ++++++------------ .../ScreenSharingViewController+Props.swift | 7 - .../ScreenSharingViewController.swift | 40 +++-- .../ScreenSharingViewModel+Environment.swift | 7 - .../ScreenSharingViewModel+Output.swift | 7 - .../ViewModel/ScreenSharingViewModel.swift | 66 ------- .../Components/BackgroundSwiftUI.swift | 24 +++ .../Buttons/ActionButtonSwiftUI.swift | 8 +- .../Buttons/HeaderButtonSwiftUI.swift | 8 +- .../Components/Header/HeaderSwiftUI.swift | 6 +- .../Extensions/View+Accessibility.swift | 92 +++++++++- .../Mocks/ScreenSharingView.Mock.swift | 15 -- .../ScreenSharingViewController.Mock.swift | 13 -- .../Mocks/ScreenSharingViewStyle+Mock.swift | 2 +- .../ScreenSharingViewModelTests.swift | 29 +-- .../VideoCall/Mocks/HeaderStyle.Mock.swift | 2 +- ...reViewControllerDynamicTypeFontTests.swift | 22 +-- ...ScreenShareViewControllerLayoutTests.swift | 22 +-- ...eenShareViewControllerVoiceOverTests.swift | 20 +-- .../SwiftPackageManager/spm-project.yml | 2 +- 35 files changed, 409 insertions(+), 407 deletions(-) create mode 100644 GliaWidgets/Sources/CallVisualizer/Mock/ScreenSharingViewModel.mock.swift create mode 100644 GliaWidgets/Sources/CallVisualizer/ScreenSharing/Model/ScreenSharingViewModel.swift rename GliaWidgets/Sources/CallVisualizer/ScreenSharing/{ => Style}/ScreenSharingViewStyle.Accessibility.swift (100%) rename GliaWidgets/Sources/CallVisualizer/ScreenSharing/{ => Style}/ScreenSharingViewStyle.swift (100%) delete mode 100644 GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController+Props.swift delete mode 100644 GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Environment.swift delete mode 100644 GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Output.swift delete mode 100644 GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel.swift create mode 100644 GliaWidgets/SwiftUI/Components/BackgroundSwiftUI.swift delete mode 100644 GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingView.Mock.swift delete mode 100644 GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewController.Mock.swift diff --git a/GliaWidgets.xcodeproj/project.pbxproj b/GliaWidgets.xcodeproj/project.pbxproj index 0a8ddefd6..bc3fc2472 100644 --- a/GliaWidgets.xcodeproj/project.pbxproj +++ b/GliaWidgets.xcodeproj/project.pbxproj @@ -311,16 +311,12 @@ 84265E07298AE96B00D65842 /* ScreenSharingViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E06298AE96B00D65842 /* ScreenSharingViewModelTests.swift */; }; 84265E4B298D7B1900D65842 /* CallVisualizer.Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E49298D7B1900D65842 /* CallVisualizer.Coordinator.swift */; }; 84265E4C298D7B1900D65842 /* CallVisualizer.Coordinator.Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E4A298D7B1900D65842 /* CallVisualizer.Coordinator.Environment.swift */; }; - 84265E5D298D7B2900D65842 /* ScreenSharingViewModel+Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E4F298D7B2900D65842 /* ScreenSharingViewModel+Environment.swift */; }; - 84265E5E298D7B2900D65842 /* ScreenSharingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E50298D7B2900D65842 /* ScreenSharingViewModel.swift */; }; - 84265E5F298D7B2900D65842 /* ScreenSharingViewModel+Output.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E51298D7B2900D65842 /* ScreenSharingViewModel+Output.swift */; }; 84265E60298D7B2900D65842 /* ScreenSharingCoordinator+Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E53298D7B2900D65842 /* ScreenSharingCoordinator+Environment.swift */; }; 84265E61298D7B2900D65842 /* ScreenSharingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E54298D7B2900D65842 /* ScreenSharingCoordinator.swift */; }; 84265E62298D7B2900D65842 /* ScreenSharingCoordinator+DelegateEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E55298D7B2900D65842 /* ScreenSharingCoordinator+DelegateEvent.swift */; }; 84265E63298D7B2900D65842 /* ScreenSharingViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E56298D7B2900D65842 /* ScreenSharingViewStyle.swift */; }; 84265E64298D7B2900D65842 /* ScreenSharingViewStyle.Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E57298D7B2900D65842 /* ScreenSharingViewStyle.Accessibility.swift */; }; 84265E65298D7B2900D65842 /* ScreenSharingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E59298D7B2900D65842 /* ScreenSharingView.swift */; }; - 84265E66298D7B2900D65842 /* ScreenSharingViewController+Props.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E5B298D7B2900D65842 /* ScreenSharingViewController+Props.swift */; }; 84265E67298D7B2900D65842 /* ScreenSharingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E5C298D7B2900D65842 /* ScreenSharingViewController.swift */; }; 84265E6B29912E2100D65842 /* RemoteConfiguration+CallVisualizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E6A29912E2100D65842 /* RemoteConfiguration+CallVisualizer.swift */; }; 84265E6E29914DDA00D65842 /* ViewController+CallVisualizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84265E6D29914DDA00D65842 /* ViewController+CallVisualizer.swift */; }; @@ -603,11 +599,12 @@ 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 */; }; + 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 */; }; - C07FA04329AF551D00E9FB7F /* ScreenSharingView.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */; }; - C07FA04629AF560A00E9FB7F /* ScreenSharingViewController.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */; }; C07FA04B29AF83B900E9FB7F /* ActionButton.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */; }; C07FA04F29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04C29B0E41A00E9FB7F /* ScreenShareViewControllerVoiceOverTests.swift */; }; C07FA05029B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07FA04D29B0E41A00E9FB7F /* VideoCallViewControllerVoiceOverTests.swift */; }; @@ -1051,16 +1048,12 @@ 84265E0B298AECBA00D65842 /* ScreenSharingViewStyle+Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScreenSharingViewStyle+Mock.swift"; sourceTree = ""; }; 84265E49298D7B1900D65842 /* CallVisualizer.Coordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallVisualizer.Coordinator.swift; sourceTree = ""; }; 84265E4A298D7B1900D65842 /* CallVisualizer.Coordinator.Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallVisualizer.Coordinator.Environment.swift; sourceTree = ""; }; - 84265E4F298D7B2900D65842 /* ScreenSharingViewModel+Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ScreenSharingViewModel+Environment.swift"; sourceTree = ""; }; - 84265E50298D7B2900D65842 /* ScreenSharingViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewModel.swift; sourceTree = ""; }; - 84265E51298D7B2900D65842 /* ScreenSharingViewModel+Output.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ScreenSharingViewModel+Output.swift"; sourceTree = ""; }; 84265E53298D7B2900D65842 /* ScreenSharingCoordinator+Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ScreenSharingCoordinator+Environment.swift"; sourceTree = ""; }; 84265E54298D7B2900D65842 /* ScreenSharingCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSharingCoordinator.swift; sourceTree = ""; }; 84265E55298D7B2900D65842 /* ScreenSharingCoordinator+DelegateEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ScreenSharingCoordinator+DelegateEvent.swift"; sourceTree = ""; }; 84265E56298D7B2900D65842 /* ScreenSharingViewStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewStyle.swift; sourceTree = ""; }; 84265E57298D7B2900D65842 /* ScreenSharingViewStyle.Accessibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewStyle.Accessibility.swift; sourceTree = ""; }; 84265E59298D7B2900D65842 /* ScreenSharingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSharingView.swift; sourceTree = ""; }; - 84265E5B298D7B2900D65842 /* ScreenSharingViewController+Props.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ScreenSharingViewController+Props.swift"; sourceTree = ""; }; 84265E5C298D7B2900D65842 /* ScreenSharingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewController.swift; sourceTree = ""; }; 84265E6A29912E2100D65842 /* RemoteConfiguration+CallVisualizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RemoteConfiguration+CallVisualizer.swift"; sourceTree = ""; }; 84265E6D29914DDA00D65842 /* ViewController+CallVisualizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewController+CallVisualizer.swift"; sourceTree = ""; }; @@ -1348,6 +1341,9 @@ C06A7585296ECC57006B69A2 /* VisitorCodeStyle.Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisitorCodeStyle.Accessibility.swift; sourceTree = ""; }; C06A7587296ECD75006B69A2 /* Theme+VisitorCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+VisitorCode.swift"; sourceTree = ""; }; C07F62452ABC322B003EFC97 /* OrientationManager.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrientationManager.Mock.swift; sourceTree = ""; }; + C07F62782AC2D2E8003EFC97 /* BackgroundSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSwiftUI.swift; sourceTree = ""; }; + C07F627C2AC2F31F003EFC97 /* ScreenSharingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewModel.swift; sourceTree = ""; }; + C07F62802AC3057C003EFC97 /* ScreenSharingViewModel.mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingViewModel.mock.swift; sourceTree = ""; }; C07F62762AC1BA2B003EFC97 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; C07F62822AC33BB9003EFC97 /* UIView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extensions.swift"; sourceTree = ""; }; C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenSharingView.Mock.swift; sourceTree = ""; }; @@ -2919,6 +2915,7 @@ children = ( 75940978298D38C2008B173A /* CallVisualizer.Environment.Mock.swift */, 75940979298D38C2008B173A /* CallVisualizer.VisitorCodeViewModel.Mock.swift */, + C07F62802AC3057C003EFC97 /* ScreenSharingViewModel.mock.swift */, ); path = Mock; sourceTree = ""; @@ -2988,8 +2985,6 @@ children = ( 84265E0B298AECBA00D65842 /* ScreenSharingViewStyle+Mock.swift */, C07FA04929AF83A400E9FB7F /* ActionButton.Mock.swift */, - C07FA04129AF550500E9FB7F /* ScreenSharingView.Mock.swift */, - C07FA04429AF55F600E9FB7F /* ScreenSharingViewController.Mock.swift */, ); path = Mocks; sourceTree = ""; @@ -3007,26 +3002,15 @@ 84265E4D298D7B2900D65842 /* ScreenSharing */ = { isa = PBXGroup; children = ( - 84265E4E298D7B2900D65842 /* ViewModel */, 84265E52298D7B2900D65842 /* Coordinator */, - 84265E56298D7B2900D65842 /* ScreenSharingViewStyle.swift */, - 84265E57298D7B2900D65842 /* ScreenSharingViewStyle.Accessibility.swift */, + C07F627A2AC2F2F4003EFC97 /* Model */, + C07F627B2AC2F301003EFC97 /* Style */, 84265E58298D7B2900D65842 /* View */, 84265E5A298D7B2900D65842 /* ViewController */, ); path = ScreenSharing; sourceTree = ""; }; - 84265E4E298D7B2900D65842 /* ViewModel */ = { - isa = PBXGroup; - children = ( - 84265E4F298D7B2900D65842 /* ScreenSharingViewModel+Environment.swift */, - 84265E50298D7B2900D65842 /* ScreenSharingViewModel.swift */, - 84265E51298D7B2900D65842 /* ScreenSharingViewModel+Output.swift */, - ); - path = ViewModel; - sourceTree = ""; - }; 84265E52298D7B2900D65842 /* Coordinator */ = { isa = PBXGroup; children = ( @@ -3048,7 +3032,6 @@ 84265E5A298D7B2900D65842 /* ViewController */ = { isa = PBXGroup; children = ( - 84265E5B298D7B2900D65842 /* ScreenSharingViewController+Props.swift */, 84265E5C298D7B2900D65842 /* ScreenSharingViewController.swift */, ); path = ViewController; @@ -3600,6 +3583,23 @@ path = extensions; sourceTree = ""; }; + C07F627A2AC2F2F4003EFC97 /* Model */ = { + isa = PBXGroup; + children = ( + C07F627C2AC2F31F003EFC97 /* ScreenSharingViewModel.swift */, + ); + path = Model; + sourceTree = ""; + }; + C07F627B2AC2F301003EFC97 /* Style */ = { + isa = PBXGroup; + children = ( + 84265E56298D7B2900D65842 /* ScreenSharingViewStyle.swift */, + 84265E57298D7B2900D65842 /* ScreenSharingViewStyle.Accessibility.swift */, + ); + path = Style; + sourceTree = ""; + }; C096B408297EBCEB00F0C552 /* CallVisualizer */ = { isa = PBXGroup; children = ( @@ -3730,6 +3730,7 @@ children = ( C0E948072AB1D69C00890026 /* Header */, C0E948022AB1D5BC00890026 /* Buttons */, + C07F62782AC2D2E8003EFC97 /* BackgroundSwiftUI.swift */, ); path = Components; sourceTree = ""; @@ -4403,9 +4404,11 @@ 8491AF132A7ACC5400CC3E72 /* Theme.OperatorChatMessageStyle.swift in Sources */, 845E2F93283FB6D000C04D56 /* Theme.Survey.Accessibility.swift in Sources */, 75940959298D386F008B173A /* UIStackView.Extensions.swift in Sources */, + C07F627D2AC2F31F003EFC97 /* ScreenSharingViewModel.swift in Sources */, 1A0C9A9125C41AB900815406 /* CallButtonBar.swift in Sources */, C0D2F0302991229F00803B47 /* VideoCallCoordinator.Environment.swift in Sources */, 1AE15E3B257A5CC900A642C0 /* AlertConfiguration.swift in Sources */, + C07F62792AC2D2E8003EFC97 /* BackgroundSwiftUI.swift in Sources */, 75AF8D1027DFF4B3009EEE2C /* Survey.ValidationErrorView.swift in Sources */, 75940986298D38C2008B173A /* VisitorCodeView.swift in Sources */, 9A8130B927D757F900220BBD /* LocalFile.Mock.swift in Sources */, @@ -4479,19 +4482,17 @@ 1A0452F025DBE268000DA0C1 /* MessageButtonStyle.swift in Sources */, EB2CBB1227D89F7D004F178E /* OnHoldOverlayStyle.swift in Sources */, 75940983298D38C2008B173A /* VisitorCodeViewModel+Delegate.swift in Sources */, - 84265E66298D7B2900D65842 /* ScreenSharingViewController+Props.swift in Sources */, C07FA04B29AF83B900E9FB7F /* ActionButton.Mock.swift in Sources */, C0D2F08C29A4EBA900803B47 /* VIdeoCallView.Environment.Mock.swift in Sources */, 313EBD552943116E008E9597 /* SecureConversations.swift in Sources */, - C07FA04329AF551D00E9FB7F /* ScreenSharingView.Mock.swift in Sources */, 7529F2B627E1EB9A004D3581 /* Survey.ButtonView.swift in Sources */, + C07F62812AC3057C003EFC97 /* ScreenSharingViewModel.mock.swift in Sources */, C49A29E42614A29700819269 /* FilePreviewView.swift in Sources */, 1A5F815F258A43E600A605DA /* Section.swift in Sources */, 1A60AFBF2566834400E53F53 /* BaseViewController.swift in Sources */, 6E60DD5627146C9D001422EF /* AlertViewController+SingleAction.swift in Sources */, 845E2F70283CF94100C04D56 /* VisitorChatMessageStyle.Accessibility.swift in Sources */, 8491AF4E2A9CB3A400CC3E72 /* SecureConversations.TranscriptModel+GVA.swift in Sources */, - 84265E5F298D7B2900D65842 /* ScreenSharingViewModel+Output.swift in Sources */, 8491AF062A77F16D00CC3E72 /* GvaGalleryCardStyle.swift in Sources */, 1A60AFF12566A4B300E53F53 /* NavigationPresenter.swift in Sources */, 1AC7A74F2582571100567FF8 /* Interactor.swift in Sources */, @@ -4602,7 +4603,6 @@ 1AA738B925790DB400E1120F /* ActionButtonStyle.swift in Sources */, C06A7582296EC856006B69A2 /* NumberSlotStyle.swift in Sources */, 1A2DA71F25EF720400032611 /* FilePickerViewModel.swift in Sources */, - 84265E5D298D7B2900D65842 /* ScreenSharingViewModel+Environment.swift in Sources */, 750C0ADD2850D53F003E0415 /* Theme.Survey.ScaleQuestion.swift in Sources */, 9A1992E927D6BCD700161AAE /* FileDownload.Mock.swift in Sources */, AF3D520D2983B3DD00AD8E69 /* FileUploader.Environment.Interface.swift in Sources */, @@ -4713,7 +4713,6 @@ 3197F7B829F7C318008EE9F7 /* SecureConversations.CommonEngagementModel.swift in Sources */, 31DD41652A57105400F92612 /* SecureConversations.TranscriptModel.Environment.swift in Sources */, 1A277A1225FA604E009FE131 /* ChatFileContentView.swift in Sources */, - 84265E5E298D7B2900D65842 /* ScreenSharingViewModel.swift in Sources */, 75B7BD802A39D5A70060794D /* Layoutable.swift in Sources */, 845876AB282A959C007AC3DF /* SingleChoiceQuestionView.Props.Accessibility.swift in Sources */, 9AB3402327FC859E006E0FE2 /* CallButtonStyle.StateStyle.Accessibility.swift in Sources */, @@ -4801,7 +4800,6 @@ 846A5C3629CB3E270049B29F /* ScreenShareHandler.Mock.swift in Sources */, C0D2F03B299149D600803B47 /* VideoCallViewModel.swift in Sources */, C0D2F02E2991221900803B47 /* VideoCallCoordinator.DelegateEvent.swift in Sources */, - C07FA04629AF560A00E9FB7F /* ScreenSharingViewController.Mock.swift in Sources */, 1A2DA73125EFA77E00032611 /* FileUploader.swift in Sources */, 1A60B0272568070800E53F53 /* UIStackView+Extensions.swift in Sources */, 75940945298D378A008B173A /* CoreSDKClient.Mock.swift in Sources */, diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index 5fbf3c006..538370f33 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -83,7 +83,8 @@ public class Glia { uiConfig: { [weak self] in self?.uiConfig }, assetsBuilder: { [weak self] in self?.assetsBuilder ?? .standard }, getCurrentEngagement: environment.coreSdk.getCurrentEngagement, - eventHandler: onEvent + eventHandler: onEvent, + orientationManager: environment.orientationManager ) ) var rootCoordinator: EngagementCoordinator? diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift index 08ce4c92d..d15265e26 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift @@ -40,7 +40,7 @@ private extension SecureConversations.ConfirmationViewSwiftUI { .frame(width: model.orientation.isPortrait ? 100.0 : 70.0) .foregroundColor(SwiftUI.Color(model.style.confirmationImageTint)) .padding(.bottom, model.orientation.isPortrait ? 32 : 8) - .accessibility(hidden: true) + .migrationAccessibilityHidden(true) } @ViewBuilder @@ -80,8 +80,8 @@ private extension SecureConversations.ConfirmationViewSwiftUI { .background(SwiftUI.Color(model.style.checkMessagesButtonStyle.backgroundColor)) .cornerRadius(4) } - .accessibility(identifier: "secureConversations_confirmationCheckMessages_button") - .accessibility(label: Text(model.style.checkMessagesButtonStyle.accessibility.label)) - .accessibility(hint: Text(model.style.checkMessagesButtonStyle.accessibility.hint)) + .migrationAccessibilityIdentifier("secureConversations_confirmationCheckMessages_button") + .migrationAccessibilityLabel(model.style.checkMessagesButtonStyle.accessibility.label) + .migrationAccessibilityHint(model.style.checkMessagesButtonStyle.accessibility.hint) } } diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift index 053cf7374..c7f2a64ab 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationViewController.swift @@ -5,9 +5,7 @@ extension SecureConversations { final class ConfirmationViewController: UIViewController { private let model: ConfirmationViewSwiftUI.Model - init( - model: ConfirmationViewSwiftUI.Model - ) { + init(model: ConfirmationViewSwiftUI.Model) { self.model = model super.init(nibName: nil, bundle: nil) } @@ -20,11 +18,10 @@ extension SecureConversations { override func loadView() { super.loadView() let hostingController: UIHostingController - let confirmationView = ConfirmationViewSwiftUI( - model: model - ) + let confirmationView = ConfirmationViewSwiftUI(model: model) hostingController = UIHostingController(rootView: confirmationView) + hostingController.willMove(toParent: self) addChild(hostingController) view.addSubview(hostingController.view) hostingController.didMove(toParent: self) diff --git a/GliaWidgets/Sources/CallVisualizer/CallVisualizer+Environment.swift b/GliaWidgets/Sources/CallVisualizer/CallVisualizer+Environment.swift index 9c376668c..79f1ecdde 100644 --- a/GliaWidgets/Sources/CallVisualizer/CallVisualizer+Environment.swift +++ b/GliaWidgets/Sources/CallVisualizer/CallVisualizer+Environment.swift @@ -23,5 +23,6 @@ extension CallVisualizer { var assetsBuilder: () -> RemoteConfiguration.AssetsBuilder var getCurrentEngagement: CoreSdkClient.GetCurrentEngagement var eventHandler: ((GliaEvent) -> Void)? + var orientationManager: OrientationManager } } diff --git a/GliaWidgets/Sources/CallVisualizer/CallVisualizer.swift b/GliaWidgets/Sources/CallVisualizer/CallVisualizer.swift index 4684b8e3a..ad8760831 100644 --- a/GliaWidgets/Sources/CallVisualizer/CallVisualizer.swift +++ b/GliaWidgets/Sources/CallVisualizer/CallVisualizer.swift @@ -57,7 +57,8 @@ public final class CallVisualizer { case .maximized: self?.environment.eventHandler?(.maximized) } - } + }, + orientationManager: environment.orientationManager ) ) }() diff --git a/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.Environment.swift b/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.Environment.swift index 079ce7f0d..cfc07aa4c 100644 --- a/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.Environment.swift +++ b/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.Environment.swift @@ -20,5 +20,6 @@ extension CallVisualizer.Coordinator { var date: () -> Date var engagedOperator: () -> CoreSdkClient.Operator? var eventHandler: (DelegateEvent) -> Void + var orientationManager: OrientationManager } } diff --git a/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.swift b/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.swift index e9a4b6f65..302b708ae 100644 --- a/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.swift +++ b/GliaWidgets/Sources/CallVisualizer/Coordinator/CallVisualizer.Coordinator.swift @@ -182,7 +182,8 @@ extension CallVisualizer { let coordinator = ScreenSharingCoordinator( environment: .init( theme: environment.viewFactory.theme, - screenShareHandler: environment.screenShareHandler + screenShareHandler: environment.screenShareHandler, + orientationManager: environment.orientationManager ) ) diff --git a/GliaWidgets/Sources/CallVisualizer/Mock/CallVisualizer.Environment.Mock.swift b/GliaWidgets/Sources/CallVisualizer/Mock/CallVisualizer.Environment.Mock.swift index 34e3d57d0..be3732d4d 100644 --- a/GliaWidgets/Sources/CallVisualizer/Mock/CallVisualizer.Environment.Mock.swift +++ b/GliaWidgets/Sources/CallVisualizer/Mock/CallVisualizer.Environment.Mock.swift @@ -21,7 +21,8 @@ extension CallVisualizer.Environment { engagedOperator: { .mock() }, uiConfig: { nil }, assetsBuilder: { .standard }, - getCurrentEngagement: CoreSdkClient.mock.getCurrentEngagement + getCurrentEngagement: CoreSdkClient.mock.getCurrentEngagement, + orientationManager: .mock() ) } diff --git a/GliaWidgets/Sources/CallVisualizer/Mock/ScreenSharingViewModel.mock.swift b/GliaWidgets/Sources/CallVisualizer/Mock/ScreenSharingViewModel.mock.swift new file mode 100644 index 000000000..e2134370e --- /dev/null +++ b/GliaWidgets/Sources/CallVisualizer/Mock/ScreenSharingViewModel.mock.swift @@ -0,0 +1,19 @@ +#if DEBUG +import SwiftUI + +extension CallVisualizer.ScreenSharingView.Model { + static func mock( + style: ScreenSharingViewStyle = .mock(), + screenSharingHandler: ScreenShareHandler = .mock + ) -> CallVisualizer.ScreenSharingView.Model { + .init( + style: style, + environment: .init( + orientationManager: .mock(), + uiApplication: .mock, + screenShareHandler: screenSharingHandler + ) + ) + } +} +#endif diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator+Environment.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator+Environment.swift index 07db8aa3c..ae170d9ac 100644 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator+Environment.swift +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator+Environment.swift @@ -4,5 +4,6 @@ extension CallVisualizer.ScreenSharingCoordinator { struct Environment { let theme: Theme let screenShareHandler: ScreenShareHandler + let orientationManager: OrientationManager } } diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator.swift index a86068077..75ab11f25 100644 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator.swift +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Coordinator/ScreenSharingCoordinator.swift @@ -6,7 +6,7 @@ extension CallVisualizer { var delegate: ((DelegateEvent) -> Void)? private let environment: Environment - private var viewModel: ScreenSharingViewModel? + private var viewModel: ScreenSharingView.Model? var viewController: ScreenSharingViewController? // MARK: - Initialization @@ -24,20 +24,25 @@ extension CallVisualizer { // MARK: - Private private func showEndScreenSharingViewController() -> ViewController { - let viewModel = ScreenSharingViewModel( - style: environment.theme.screenSharing, - environment: .init(screenShareHandler: environment.screenShareHandler) + let environment: ScreenSharingView.Model.Environment = .init( + orientationManager: self.environment.orientationManager, + uiApplication: .live, + screenShareHandler: environment.screenShareHandler + ) + let model: ScreenSharingView.Model = .init( + style: self.environment.theme.screenSharing, + environment: environment ) - self.viewModel = viewModel + self.viewModel = model - let viewController = ScreenSharingViewController(props: viewModel.props()) + let viewController: ScreenSharingViewController = .init(model: model) viewController.modalPresentationStyle = .overFullScreen self.viewController = viewController - viewModel.delegate = .init { [weak self, weak viewController] event in + model.delegate = .init { [weak self, weak viewController] event in switch event { - case .close: + case .closeTapped: viewController?.dismiss(animated: true) self?.delegate?(.close) } @@ -45,19 +50,5 @@ extension CallVisualizer { return viewController } - - private static func createHeaderProps(with header: HeaderStyle) -> Header.Props { - let backButton = header.backButton.map { HeaderButton.Props(style: $0) } - - return .init( - title: "", - effect: .none, - endButton: .init(), - backButton: backButton, - closeButton: .init(style: header.closeButton), - endScreenshareButton: .init(style: header.endScreenShareButton), - style: header - ) - } } } diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Model/ScreenSharingViewModel.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Model/ScreenSharingViewModel.swift new file mode 100644 index 000000000..1be19193a --- /dev/null +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Model/ScreenSharingViewModel.swift @@ -0,0 +1,110 @@ +import SwiftUI +import Combine + +extension CallVisualizer.ScreenSharingView { + final class Model: ObservableObject { + @Published private(set) var orientation: UIInterfaceOrientation + let style: ScreenSharingViewStyle + let environment: Environment + let orientationManager: OrientationManager + var delegate: Command = .nop + var cancellables: Set = [] + + init(style: ScreenSharingViewStyle, environment: Environment) { + self.style = style + self.environment = environment + self.orientationManager = environment.orientationManager + self.orientation = orientationManager.orientation + + orientationManager.$orientation + .sink { [weak self] orientation in + self?.orientation = orientation + } + .store(in: &self.cancellables) + } + } +} + +extension CallVisualizer.ScreenSharingView.Model { + func event(_ event: Event) { + switch event { + case .closeTapped: + delegate(.closeTapped) + case .endScreenShareTapped: + endScreenSharing() + } + } + + func makeHeaderModel() -> HeaderSwiftUI.Model { + let endButtonProps: ActionButtonSwiftUI.Model = .init( + style: style.header.endButton, + accessibilityIdentifier: "header_end_button", + isEnabled: false, + isHidden: true + ) + + var backButton: HeaderButtonSwiftUI.Model? + if let endButtonStyle = style.header.backButton { + backButton = .init( + tap: Cmd { [weak self] in + self?.delegate(.closeTapped) + }, + style: endButtonStyle, + accessibilityIdentifier: "header_back_button", + size: .init(width: 20, height: 20), + isEnabled: true, + isHidden: false + ) + } + + let closeButtonProps: HeaderButtonSwiftUI.Model = .init( + style: style.header.closeButton, + accessibilityIdentifier: "header_close_button", + isEnabled: false, + isHidden: true + ) + + let endScreenShareButtonProps: HeaderButtonSwiftUI.Model = .init( + style: style.header.endScreenShareButton, + accessibilityIdentifier: "header_end_screen_sharing_button", + isEnabled: false, + isHidden: true + ) + + let environment: HeaderSwiftUI.Environment = .init(uiApplication: environment.uiApplication) + + return .init( + title: style.title, + effect: .none, + endButton: endButtonProps, + backButton: backButton, + closeButton: closeButtonProps, + endScreenshareButton: endScreenShareButtonProps, + style: style.header, + environment: environment + ) + } +} + +private extension CallVisualizer.ScreenSharingView.Model { + func endScreenSharing() { + environment.screenShareHandler.stop(nil) + } +} + +extension CallVisualizer.ScreenSharingView.Model { + struct Environment { + let orientationManager: OrientationManager + let uiApplication: UIKitBased.UIApplication + let screenShareHandler: ScreenShareHandler + } + + enum DelegateEvent { + case closeTapped + } + + enum Event { + case closeTapped + case endScreenShareTapped + } +} diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ScreenSharingViewStyle.Accessibility.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Style/ScreenSharingViewStyle.Accessibility.swift similarity index 100% rename from GliaWidgets/Sources/CallVisualizer/ScreenSharing/ScreenSharingViewStyle.Accessibility.swift rename to GliaWidgets/Sources/CallVisualizer/ScreenSharing/Style/ScreenSharingViewStyle.Accessibility.swift diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ScreenSharingViewStyle.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/Style/ScreenSharingViewStyle.swift similarity index 100% rename from GliaWidgets/Sources/CallVisualizer/ScreenSharing/ScreenSharingViewStyle.swift rename to GliaWidgets/Sources/CallVisualizer/ScreenSharing/Style/ScreenSharingViewStyle.swift diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift index 86fcc7a7d..033f18f7c 100644 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/View/ScreenSharingView.swift @@ -1,127 +1,59 @@ -import UIKit +import SwiftUI extension CallVisualizer { - final class ScreenSharingView: BaseView { - - // MARK: - Props - - struct Props: Equatable { - let style: ScreenSharingViewStyle - let header: Header.Props - let endScreenSharing: ActionButton.Props - - init( - style: ScreenSharingViewStyle, - header: Header.Props, - endScreenSharing: ActionButton.Props - ) { - self.style = style - self.header = header - self.endScreenSharing = endScreenSharing - } - } - - // MARK: - Properties - - private lazy var header = Header(props: props.header) - .make { header in - header.endScreenShareButton.isHidden = true - header.closeButton.isHidden = true - header.endButton.isHidden = true - } - private lazy var messageLabel = UILabel().make { - $0.font = props.style.messageTextFont - $0.textColor = props.style.messageTextColor - $0.text = props.style.messageText - $0.adjustsFontSizeToFitWidth = true - $0.numberOfLines = 2 - $0.textAlignment = .center - $0.accessibilityIdentifier = "end_screen_sharing_message" - $0.translatesAutoresizingMaskIntoConstraints = false - } - private lazy var endScreenSharingButton = ActionButton(props: props.endScreenSharing).make { - $0.setImage(props.style.buttonIcon, for: .normal) - $0.tintColor = props.style.buttonStyle.titleColor - $0.titleEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 0) - $0.titleLabel?.numberOfLines = 0 - $0.titleLabel?.translatesAutoresizingMaskIntoConstraints = false - $0.accessibilityIdentifier = "end_screen_sharing_button" - $0.accessibilityLabel = Localization.ScreenSharing.VisitorScreen.End.title - $0.accessibilityHint = Localization.ScreenSharing.VisitorScreen.End.Accessibility.hint - } - private lazy var contentStackView = UIStackView.make( - .vertical, - spacing: 16 - )( - messageLabel, - endScreenSharingButton - ) - - var props: Props { - didSet { - renderProps() - } - } - - // MARK: - Initialization - - init(props: Props) { - self.props = props - super.init() - } - - required init() { - fatalError("init() has not been implemented") - } - - // MARK: - Overrides - - override func setup() { - super.setup() - - addSubview(header) - header.translatesAutoresizingMaskIntoConstraints = false - var constraints = [NSLayoutConstraint](); defer { constraints.activate() } - constraints += header.layoutInSuperview(edges: .horizontal) - - addSubview(contentStackView) - contentStackView.translatesAutoresizingMaskIntoConstraints = false - constraints += contentStackView.centerXAnchor.constraint(equalTo: centerXAnchor) - constraints += contentStackView.centerYAnchor.constraint(equalTo: centerYAnchor) - constraints += contentStackView.layoutIn(layoutMarginsGuide, edges: .horizontal, insets: .init(top: 0, left: 42, bottom: 0, right: 42)) - - constraints += endScreenSharingButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 40) - - if let imageView = endScreenSharingButton.imageView { - constraints += imageView.widthAnchor.constraint(equalToConstant: 24) - } - - setFontScalingEnabled( - props.style.accessibility.isFontScalingEnabled, - for: messageLabel - ) - setFontScalingEnabled( - props.style.buttonStyle.accessibility.isFontScalingEnabled, - for: endScreenSharingButton - ) - } - - override func layoutSubviews() { - switch props.style.backgroundColor { - case .fill(let color): - backgroundColor = color - case .gradient(let colors): - makeGradientBackground(colors: colors) + struct ScreenSharingView: View { + @ObservedObject var model: Model + + var body: some View { + ZStack { + Background(model.style.backgroundColor) + .edgesIgnoringSafeArea(.all) + VStack(spacing: 0) { + HeaderSwiftUI(model: model.makeHeaderModel()) + VStack(spacing: 16) { + mainLabel + endScreenShareButton + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + }.edgesIgnoringSafeArea(.top) } } } } -// MARK: - Private +extension CallVisualizer.ScreenSharingView { + var mainLabel: some View { + Text(model.style.messageText) + .font(.convert(model.style.messageTextFont)) + .foregroundColor(SwiftUI.Color(model.style.messageTextColor)) + .lineLimit(2) + .multilineTextAlignment(.center) + .migrationAccessibilityIdentifier("end_screen_sharing_message") + } -private extension CallVisualizer.ScreenSharingView { - func renderProps() { - header.props = props.header - endScreenSharingButton.props = props.endScreenSharing + var endScreenShareButton: some View { + SwiftUI.Button(action: { + model.event(.endScreenShareTapped) + }, label: { + HStack(spacing: 8) { + SwiftUI.Image(uiImage: model.style.buttonIcon) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 24) + .foregroundColor(SwiftUI.Color(model.style.buttonStyle.titleColor)) + Text(model.style.buttonStyle.title) + .font(.convert(model.style.buttonStyle.titleFont)) + .foregroundColor(SwiftUI.Color(model.style.buttonStyle.titleColor)) + .lineLimit(nil) + } + .padding(.horizontal, 4) + .frame(maxWidth: .infinity, minHeight: 40, idealHeight: 40) + .background(Background(model.style.buttonStyle.backgroundColor)) + .cornerRadius(4) + .padding(.horizontal, 60) + }) + .migrationAccessibilityIdentifier("end_screen_sharing_button") + .migrationAccessibilityLabel(L10n.CallVisualizer.ScreenSharing.Accessibility.buttonLabel) + .migrationAccessibilityHint(L10n.CallVisualizer.ScreenSharing.Accessibility.buttonHint) } } diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController+Props.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController+Props.swift deleted file mode 100644 index a6a8c2969..000000000 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController+Props.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -extension CallVisualizer.ScreenSharingViewController { - struct Props: Equatable { - let screenSharingViewProps: CallVisualizer.ScreenSharingView.Props - } -} diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController.swift index 8d206c6c6..a2e726bff 100644 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController.swift +++ b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewController/ScreenSharingViewController.swift @@ -1,38 +1,42 @@ import UIKit +import SwiftUI extension CallVisualizer { final class ScreenSharingViewController: UIViewController { - private lazy var screenSharingView = ScreenSharingView(props: props.screenSharingViewProps) - private var props: Props + let model: ScreenSharingView.Model // MARK: - Initialization - init(props: Props) { - self.props = props - super.init(nibName: "", bundle: nil) + init( + model: ScreenSharingView.Model + ) { + self.model = model + super.init(nibName: nil, bundle: nil) } + @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - View lifecycle - override func loadView() { - view = screenSharingView - } - override func viewDidLoad() { super.viewDidLoad() - renderProps() + let hostingController: UIHostingController + let screenSharingView = ScreenSharingView(model: model) + hostingController = UIHostingController(rootView: screenSharingView) + hostingController.willMove(toParent: self) + addChild(hostingController) + view.addSubview(hostingController.view) + hostingController.didMove(toParent: self) + hostingController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + hostingController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor) + ]) } } } - -// MARK: - Private - -private extension CallVisualizer.ScreenSharingViewController { - func renderProps() { - screenSharingView.props = props.screenSharingViewProps - } -} diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Environment.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Environment.swift deleted file mode 100644 index 4229ab78a..000000000 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Environment.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -extension CallVisualizer.ScreenSharingViewModel { - struct Environment { - let screenShareHandler: ScreenShareHandler - } -} diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Output.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Output.swift deleted file mode 100644 index eb87e8234..000000000 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel+Output.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -extension CallVisualizer.ScreenSharingViewModel { - enum DelegateEvent { - case close - } -} diff --git a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel.swift b/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel.swift deleted file mode 100644 index 03288bc7f..000000000 --- a/GliaWidgets/Sources/CallVisualizer/ScreenSharing/ViewModel/ScreenSharingViewModel.swift +++ /dev/null @@ -1,66 +0,0 @@ -import Foundation - -extension CallVisualizer { - final class ScreenSharingViewModel { - typealias Props = CallVisualizer.ScreenSharingViewController.Props - - private let environment: Environment - private let style: ScreenSharingViewStyle - - var delegate: Command = .nop - - init( - style: ScreenSharingViewStyle, - environment: Environment - ) { - self.style = style - self.environment = environment - } - } -} - -// MARK: - Private - -extension CallVisualizer.ScreenSharingViewModel { - func props() -> Props { - let backButton = style.header.backButton.map { - HeaderButton.Props( - tap: Cmd { [weak self] in self?.delegate(.close) }, - style: $0 - ) - } - - let headerProps = Header.Props( - title: style.title, - effect: .none, - endButton: .init(style: style.header.endButton), - backButton: backButton, - closeButton: .init( - style: style.header.closeButton - ), - endScreenshareButton: .init( - tap: Cmd { [weak self] in self?.endScreenSharing() }, - style: style.header.endScreenShareButton - ), - style: style.header - ) - let endScreenSharingButtonProps = ActionButton.Props( - style: style.buttonStyle, - tap: Cmd { [weak self] in self?.endScreenSharing() } - ) - - let screenSharingViewProps = CallVisualizer.ScreenSharingView.Props( - style: style, - header: headerProps, - endScreenSharing: endScreenSharingButtonProps - ) - - return Props( - screenSharingViewProps: screenSharingViewProps - ) - } - - func endScreenSharing() { - environment.screenShareHandler.stop(nil) - } -} diff --git a/GliaWidgets/SwiftUI/Components/BackgroundSwiftUI.swift b/GliaWidgets/SwiftUI/Components/BackgroundSwiftUI.swift new file mode 100644 index 000000000..bbce1869d --- /dev/null +++ b/GliaWidgets/SwiftUI/Components/BackgroundSwiftUI.swift @@ -0,0 +1,24 @@ +import SwiftUI + +struct Background: View { + let colorType: ColorType + + init(_ colorType: ColorType) { + self.colorType = colorType + } + var body: some View { + switch colorType { + case .fill(let color): + SwiftUI.Color(color) + case .gradient(let colors): + let convertedColors = colors + .map { UIColor(cgColor: $0) } + .map { SwiftUI.Color($0) } + LinearGradient( + colors: convertedColors, + startPoint: .top, + endPoint: .bottom + ) + } + } +} diff --git a/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift index 77fe8c833..377436d00 100644 --- a/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift +++ b/GliaWidgets/SwiftUI/Components/Buttons/ActionButtonSwiftUI.swift @@ -25,10 +25,10 @@ struct ActionButtonSwiftUI: View { x: model.style.shadowOffset?.width ?? 0, y: model.style.shadowOffset?.height ?? 0 ) - .accessibility(identifier: model.accessibilityIdentifier) - .accessibility(addTraits: .isButton) - .accessibility(removeTraits: .isImage) - .onTapGesture(perform: model.tap.callAsFunction) + .migrationAccessibilityIdentifier(model.accessibilityIdentifier) + .migrationAccessibilityAddTrait(.isButton) + .migrationAccessibilityRemoveTrait(.isImage) + .onTapGesture(perform: model.tap.execute) } } diff --git a/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift index fd71f847b..e72df6cea 100644 --- a/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift +++ b/GliaWidgets/SwiftUI/Components/Buttons/HeaderButtonSwiftUI.swift @@ -16,11 +16,11 @@ struct HeaderButtonSwiftUI: View { .contentShape(Rectangle()) .foregroundColor(SwiftUI.Color(model.style.color)) .opacity(model.isEnabled ? 1.0 : 0.6) - .accessibility(label: Text(model.style.accessibility.label)) - .accessibility(addTraits: .isButton) - .accessibility(removeTraits: .isImage) - .onTapGesture(perform: model.tap.execute) + .migrationAccessibilityLabel(model.style.accessibility.label) + .migrationAccessibilityAddTrait(.isButton) + .migrationAccessibilityRemoveTrait(.isImage) .migrationAccessibilityIdentifier(model.accessibilityIdentifier) + .onTapGesture(perform: model.tap.execute) } } diff --git a/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift b/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift index 1c64e7d3f..f0c436937 100644 --- a/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift +++ b/GliaWidgets/SwiftUI/Components/Header/HeaderSwiftUI.swift @@ -26,9 +26,9 @@ struct HeaderSwiftUI: View { Text(model.title) .font(.convert(model.style.titleFont)) .foregroundColor(SwiftUI.Color(model.style.titleColor)) - .accessibility(identifier: "header_view_title_label") - .accessibility(label: Text(model.title)) - .accessibility(addTraits: .isHeader) + .migrationAccessibilityIdentifier("header_view_title_label") + .migrationAccessibilityLabel(model.title) + .migrationAccessibilityAddTrait(.isHeader) } .padding(.horizontal, 16) .padding(.bottom, 12) diff --git a/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift b/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift index e50c5c34e..583181a50 100644 --- a/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift +++ b/GliaWidgets/SwiftUI/Extensions/View+Accessibility.swift @@ -14,9 +14,99 @@ struct MigrationAccessibilityIdentifierModifier: ViewModifier { } } -/// Modifier for specifying accessibility identifier for avoiding deprecation warning. +/// Accessibility label view modifier for resolving between +/// deprecated and new method to specify accessibility label. +struct MigrationAccessibilityLabelModifier: ViewModifier { + let label: String + + func body(content: Content) -> some View { + if #available(iOS 14, *) { + content.accessibilityLabel(label) + } else { + content.accessibility(label: .init(label)) + } + } +} + +/// Accessibility hint view modifier for resolving between +/// deprecated and new method to specify accessibility hint. +struct MigrationAccessibilityHintModifier: ViewModifier { + let hint: String + + func body(content: Content) -> some View { + if #available(iOS 14, *) { + content.accessibilityHint(hint) + } else { + content.accessibility(hint: .init(hint)) + } + } +} + +/// Accessibility addTraits view modifier for resolving between +/// deprecated and new method to add accessibility traits. +struct MigrationAccessibilityAddTraitModifier: ViewModifier { + let trait: AccessibilityTraits + + func body(content: Content) -> some View { + if #available(iOS 14, *) { + content.accessibilityAddTraits(trait) + } else { + content.accessibility(addTraits: trait) + } + } +} + +/// Accessibility removeTraits view modifier for resolving between +/// deprecated and new method to accessibility traits. +struct MigrationAccessibilityDropTraitModifier: ViewModifier { + let trait: AccessibilityTraits + + func body(content: Content) -> some View { + if #available(iOS 14, *) { + content.accessibilityRemoveTraits(trait) + } else { + content.accessibility(removeTraits: trait) + } + } +} + +/// Accessibility hidden view modifier for resolving between +/// deprecated and new method to hidden or show accessibility. +struct MigrationAccessibilityHiddenModifier: ViewModifier { + let isHidden: Bool + + func body(content: Content) -> some View { + if #available(iOS 14, *) { + content.accessibilityHidden(isHidden) + } else { + content.accessibility(hidden: isHidden) + } + } +} + +/// Modifiers for specifying accessibility for avoiding deprecation warning. extension View { func migrationAccessibilityIdentifier(_ identifier: String) -> some View { self.modifier(MigrationAccessibilityIdentifierModifier(identifier: identifier)) } + + func migrationAccessibilityLabel(_ label: String) -> some View { + self.modifier(MigrationAccessibilityLabelModifier(label: label)) + } + + func migrationAccessibilityHint(_ hint: String) -> some View { + self.modifier(MigrationAccessibilityHintModifier(hint: hint)) + } + + func migrationAccessibilityAddTrait(_ trait: AccessibilityTraits) -> some View { + self.modifier(MigrationAccessibilityAddTraitModifier(trait: trait)) + } + + func migrationAccessibilityRemoveTrait(_ trait: AccessibilityTraits) -> some View { + self.modifier(MigrationAccessibilityDropTraitModifier(trait: trait)) + } + + func migrationAccessibilityHidden(_ isHidden: Bool) -> some View { + self.modifier(MigrationAccessibilityHiddenModifier(isHidden: isHidden)) + } } diff --git a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingView.Mock.swift b/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingView.Mock.swift deleted file mode 100644 index 37436e052..000000000 --- a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingView.Mock.swift +++ /dev/null @@ -1,15 +0,0 @@ -#if DEBUG - -import UIKit - -extension CallVisualizer.ScreenSharingView.Props { - static func mock( - style: ScreenSharingViewStyle = .mock(), - header: Header.Props = .mock(), - endScreenSharing: ActionButton.Props = .mock() - ) -> CallVisualizer.ScreenSharingView.Props { - return .init(style: style, header: header, endScreenSharing: endScreenSharing) - } -} - -#endif diff --git a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewController.Mock.swift b/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewController.Mock.swift deleted file mode 100644 index e9c084e3c..000000000 --- a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewController.Mock.swift +++ /dev/null @@ -1,13 +0,0 @@ -#if DEBUG - -import UIKit - -extension CallVisualizer.ScreenSharingViewController.Props { - static func mock( - screenShareViewProps: CallVisualizer.ScreenSharingView.Props = .mock() - ) -> CallVisualizer.ScreenSharingViewController.Props { - return .init(screenSharingViewProps: screenShareViewProps) - } -} - -#endif diff --git a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift b/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift index a7bead115..731cc44ae 100644 --- a/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/ScreenSharing/Mocks/ScreenSharingViewStyle+Mock.swift @@ -4,7 +4,7 @@ import UIKit extension ScreenSharingViewStyle { static func mock( - title: String = "", + title: String = "Screen Sharing", messageTextFont: UIFont = .systemFont(ofSize: 20, weight: .medium), buttonTitleFont: UIFont = .systemFont(ofSize: 16, weight: .regular) ) -> ScreenSharingViewStyle { diff --git a/GliaWidgetsTests/CallVisualizer/ScreenSharing/ScreenSharingViewModelTests.swift b/GliaWidgetsTests/CallVisualizer/ScreenSharing/ScreenSharingViewModelTests.swift index 2ad63a3c2..772f204e4 100644 --- a/GliaWidgetsTests/CallVisualizer/ScreenSharing/ScreenSharingViewModelTests.swift +++ b/GliaWidgetsTests/CallVisualizer/ScreenSharing/ScreenSharingViewModelTests.swift @@ -3,12 +3,11 @@ import XCTest final class ScreenSharingViewModelTests: XCTestCase { - private var viewModel: CallVisualizer.ScreenSharingViewModel! + private var model: CallVisualizer.ScreenSharingView.Model! override func tearDownWithError() throws { try super.tearDownWithError() - - viewModel = nil + model = nil } func test_end_screen_sharing() throws { @@ -18,15 +17,9 @@ final class ScreenSharingViewModelTests: XCTestCase { isRunning = false } - viewModel = CallVisualizer.ScreenSharingViewModel( - style: ScreenSharingViewStyle.mock(), - environment: .init(screenShareHandler: screenShareHandlerMock) - ) - - let props = viewModel.props() - + model = .mock(screenSharingHandler: screenShareHandlerMock) XCTAssertTrue(isRunning) - props.screenSharingViewProps.endScreenSharing.tap.execute() + model.event(.endScreenShareTapped) XCTAssertFalse(isRunning) } @@ -34,20 +27,14 @@ final class ScreenSharingViewModelTests: XCTestCase { enum Call { case close } var calls: [Call] = [] - viewModel = CallVisualizer.ScreenSharingViewModel( - style: .mock(), - environment: .init(screenShareHandler: ScreenShareHandler.mock) - ) - viewModel.delegate = Command { event in + model = .mock() + model.delegate = Command { event in switch event { - case .close: + case .closeTapped: calls.append(.close) } } - let props = viewModel.props() - - props.screenSharingViewProps.endScreenSharing.tap.execute() - props.screenSharingViewProps.header.backButton?.tap() + model.event(.closeTapped) XCTAssertEqual(calls, [.close]) } } diff --git a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift index 62e17e3ec..65a5cdb9e 100644 --- a/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift +++ b/GliaWidgetsTests/CallVisualizer/VideoCall/Mocks/HeaderStyle.Mock.swift @@ -26,7 +26,7 @@ extension HeaderStyle { extension HeaderButtonStyle { static func mock( - image: UIImage = .mock, + image: UIImage = Asset.back.image, color: UIColor = .white, accessibility: Accessibility = .init(label: "", hint: "") ) -> HeaderButtonStyle { diff --git a/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift b/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift index 4ffcbab25..1df4baf23 100644 --- a/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift +++ b/SnapshotTests/ScreenShareViewControllerDynamicTypeFontTests.swift @@ -5,24 +5,10 @@ import XCTest // swiftlint:disable type_name final class ScreenShareViewControllerDynamicTypeFontTests: SnapshotTestCase { func testScreenShareViewController_extra3Large() { - let theme = Theme() - let font = theme.font - let props: CallVisualizer.ScreenSharingViewController.Props = .init( - screenSharingViewProps: .init( - style: .mock( - messageTextFont: font.header2, - buttonTitleFont: font.bodyText - ), - header: .mock( - title: L10n.CallVisualizer.ScreenSharing.title, - backButton: .init(style: .mock(image: Asset.back.image)) - ), - endScreenSharing: .mock(style: .mock(titleFont: font.bodyText)) - ) - ) - let screenShareViewController = CallVisualizer.ScreenSharingViewController(props: props) - screenShareViewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) - screenShareViewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) + let model: CallVisualizer.ScreenSharingView.Model = .mock() + let viewController: CallVisualizer.ScreenSharingViewController = .init(model: model) + viewController.assertSnapshot(as: .extra3LargeFont, in: .portrait) + viewController.assertSnapshot(as: .extra3LargeFont, in: .landscape) } } // swiftlint:enable type_name diff --git a/SnapshotTests/ScreenShareViewControllerLayoutTests.swift b/SnapshotTests/ScreenShareViewControllerLayoutTests.swift index dd64fab18..cd210b7f0 100644 --- a/SnapshotTests/ScreenShareViewControllerLayoutTests.swift +++ b/SnapshotTests/ScreenShareViewControllerLayoutTests.swift @@ -4,23 +4,9 @@ import XCTest final class ScreenShareViewControllerLayoutTests: SnapshotTestCase { func testScreenShareViewController() { - let theme = Theme() - let font = theme.font - let props: CallVisualizer.ScreenSharingViewController.Props = .init( - screenSharingViewProps: .init( - style: .mock( - messageTextFont: font.header2, - buttonTitleFont: font.bodyText - ), - header: .mock( - title: L10n.CallVisualizer.ScreenSharing.title, - backButton: .init(style: .mock(image: Asset.back.image)) - ), - endScreenSharing: .mock(style: .mock(titleFont: font.bodyText)) - ) - ) - let screenShareViewController = CallVisualizer.ScreenSharingViewController(props: props) - screenShareViewController.assertSnapshot(as: .image, in: .portrait) - screenShareViewController.assertSnapshot(as: .image, in: .landscape) + let model: CallVisualizer.ScreenSharingView.Model = .mock() + let viewController: CallVisualizer.ScreenSharingViewController = .init(model: model) + viewController.assertSnapshot(as: .image, in: .portrait) + viewController.assertSnapshot(as: .image, in: .landscape) } } diff --git a/SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift b/SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift index 5ca81ba33..b124aa601 100644 --- a/SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift +++ b/SnapshotTests/ScreenShareViewControllerVoiceOverTests.swift @@ -5,22 +5,8 @@ import XCTest final class ScreenShareViewControllerVoiceOverTests: SnapshotTestCase { func testScreenShareViewController() { - let theme = Theme() - let font = theme.font - let props: CallVisualizer.ScreenSharingViewController.Props = .init( - screenSharingViewProps: .init( - style: .mock( - messageTextFont: font.header2, - buttonTitleFont: font.bodyText - ), - header: .mock( - title: L10n.CallVisualizer.ScreenSharing.title, - backButton: .init(style: .mock(image: Asset.back.image)) - ), - endScreenSharing: .mock(style: .mock(titleFont: font.bodyText)) - ) - ) - let screenShareViewController = CallVisualizer.ScreenSharingViewController(props: props) - screenShareViewController.assertSnapshot(as: .accessibilityImage) + let model: CallVisualizer.ScreenSharingView.Model = .mock() + let viewController: CallVisualizer.ScreenSharingViewController = .init(model: model) + viewController.assertSnapshot(as: .accessibilityImage) } } diff --git a/integrations/SwiftPackageManager/spm-project.yml b/integrations/SwiftPackageManager/spm-project.yml index 5299ddfee..b6df53c14 100644 --- a/integrations/SwiftPackageManager/spm-project.yml +++ b/integrations/SwiftPackageManager/spm-project.yml @@ -8,7 +8,7 @@ targets: SpmSampleApp: type: application platform: iOS - deploymentTarget: "12.0" + deploymentTarget: "13.0" info: path: Sources/Info.plist sources: [Sources] From d39c9cf90150e14e1727d914ed10324b7537a817 Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Wed, 20 Sep 2023 12:34:51 +0300 Subject: [PATCH 23/40] Apply Global colors to all views Global colors were not applied to all views and this PR fixes this issue MOB-2679 --- GliaWidgets/Color.swift | 4 +-- .../Theme+SecureConversationsWelcome.swift | 12 +++---- .../RemoteConfiguration.swift | 2 +- .../Sources/Theme/Survey/Theme+Survey.swift | 2 +- .../Survey/Theme.Survey.InputQuestion.swift | 2 +- GliaWidgets/Sources/Theme/Theme+Alert.swift | 2 +- .../Theme/Theme+AlertConfiguration.swift | 4 +-- GliaWidgets/Sources/Theme/Theme+Chat.swift | 34 +++++++++---------- GliaWidgets/Sources/Theme/Theme+Gva.swift | 22 ++++++------ .../Sources/Theme/Theme+VisitorCode.swift | 10 ++---- GliaWidgets/Sources/Theme/Theme.swift | 4 +-- GliaWidgets/Sources/Theme/ThemeColor.swift | 12 ++----- .../Settings/SettingsViewController.swift | 3 +- 13 files changed, 50 insertions(+), 63 deletions(-) diff --git a/GliaWidgets/Color.swift b/GliaWidgets/Color.swift index 0f92d83b9..b2fc2b771 100644 --- a/GliaWidgets/Color.swift +++ b/GliaWidgets/Color.swift @@ -8,7 +8,5 @@ enum Color { static let baseNormal = UIColor(hex: 0x6C7683) // grey static let baseShade = UIColor(hex: 0x6C7683, alpha: 0.5) static let baseDark = UIColor(hex: 0x2C0735) // purple - static let lightGrey = UIColor(hex: 0xF3F3F3) // light gray - static let grey = UIColor(hex: 0x999999) // gray - static let background: UIColor = .white + static let baseNeutral = UIColor(hex: 0xF3F3F3) // light gray } diff --git a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift index 448b677d1..e418b6be1 100644 --- a/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift +++ b/GliaWidgets/SecureConversations/Welcome/Theme+SecureConversationsWelcome.swift @@ -54,7 +54,7 @@ extension Theme { borderColor: color.baseNormal, borderWidth: 1, cornerRadius: 4, - backgroundColor: color.background, + backgroundColor: color.baseLight, accessibility: .init(isFontScalingEnabled: true) ) @@ -68,7 +68,7 @@ extension Theme { borderColor: color.primary, borderWidth: 1, cornerRadius: 4, - backgroundColor: color.background, + backgroundColor: color.baseLight, accessibility: .init(isFontScalingEnabled: true) ) @@ -178,7 +178,7 @@ extension Theme { errorIcon: Asset.uploadError.image, errorIconColor: color.systemNegative, backgroundColor: color.primary, - errorBackgroundColor: Color.lightGrey, + errorBackgroundColor: color.baseNeutral, accessibility: .init(isFontScalingEnabled: true) ) let uploading = FileUploadStateStyle( @@ -214,7 +214,7 @@ extension Theme { error: error, progressColor: color.primary, errorProgressColor: color.systemNegative, - progressBackgroundColor: Color.lightGrey, + progressBackgroundColor: color.baseNeutral, removeButtonImage: Asset.mcRemoveUpload.image, removeButtonColor: color.baseNormal, backgroundColor: .commonGray, @@ -267,7 +267,7 @@ extension Theme { return AttachmentSourceListStyle( items: [pickPhoto, takePhoto, browse], separatorColor: color.baseShade, - backgroundColor: Color.lightGrey + backgroundColor: color.baseNeutral ) } @@ -285,7 +285,7 @@ extension Theme { filePickerButtonStyle: filePickerButtonStyle, attachmentListStyle: uploadListStyle, pickMediaStyle: pickMediaStyle, - backgroundColor: color.background + backgroundColor: color.baseLight ) } } diff --git a/GliaWidgets/Sources/RemoteConfiguration/RemoteConfiguration.swift b/GliaWidgets/Sources/RemoteConfiguration/RemoteConfiguration.swift index 4b78ad3cf..c25bb8a3a 100644 --- a/GliaWidgets/Sources/RemoteConfiguration/RemoteConfiguration.swift +++ b/GliaWidgets/Sources/RemoteConfiguration/RemoteConfiguration.swift @@ -20,8 +20,8 @@ extension RemoteConfiguration { let baseLight: String? let baseDark: String? let baseShade: String? - let background: String? let systemNegative: String? + let baseNeutral: String? } } diff --git a/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift b/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift index 563428bf5..d5238d6bd 100644 --- a/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift +++ b/GliaWidgets/Sources/Theme/Survey/Theme+Survey.swift @@ -56,7 +56,7 @@ extension Theme.SurveyStyle { return .init( layer: .init( - background: .fill(color: color.background), + background: .fill(color: color.baseLight), borderColor: color.baseDark.cgColor, cornerRadius: 30 ), diff --git a/GliaWidgets/Sources/Theme/Survey/Theme.Survey.InputQuestion.swift b/GliaWidgets/Sources/Theme/Survey/Theme.Survey.InputQuestion.swift index f164bccf4..6fde7c07d 100644 --- a/GliaWidgets/Sources/Theme/Survey/Theme.Survey.InputQuestion.swift +++ b/GliaWidgets/Sources/Theme/Survey/Theme.Survey.InputQuestion.swift @@ -33,7 +33,7 @@ public extension Theme.SurveyStyle { accessibility: .init(isFontScalingEnabled: true) ), normalLayer: .init( - background: .fill(color: Color.baseLight), + background: .fill(color: color.baseLight), borderColor: color.baseNormal.cgColor, borderWidth: 1, cornerRadius: 4 diff --git a/GliaWidgets/Sources/Theme/Theme+Alert.swift b/GliaWidgets/Sources/Theme/Theme+Alert.swift index 5f5da0a23..eeada367f 100644 --- a/GliaWidgets/Sources/Theme/Theme+Alert.swift +++ b/GliaWidgets/Sources/Theme/Theme+Alert.swift @@ -31,7 +31,7 @@ extension Theme { titleImageColor: color.primary, messageFont: font.bodyText, messageColor: color.baseDark, - backgroundColor: .fill(color: color.background), + backgroundColor: .fill(color: color.baseLight), closeButtonColor: .fill(color: color.baseNormal), actionAxis: .horizontal, positiveAction: positiveAction, diff --git a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift index d70056d0c..61b226442 100644 --- a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift +++ b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift @@ -41,7 +41,7 @@ extension Theme { infoFont: font.subtitle, infoColor: color.baseDark, borderColor: color.primary, - backgroundColor: color.background, + backgroundColor: color.baseLight, icon: Asset.upgradeAudio.image, iconColor: color.primary ) @@ -53,7 +53,7 @@ extension Theme { infoFont: font.subtitle, infoColor: color.baseDark, borderColor: color.primary, - backgroundColor: color.background, + backgroundColor: color.baseLight, icon: Asset.upgradePhone.image, iconColor: color.primary ) diff --git a/GliaWidgets/Sources/Theme/Theme+Chat.swift b/GliaWidgets/Sources/Theme/Theme+Chat.swift index a14f32063..edad47781 100644 --- a/GliaWidgets/Sources/Theme/Theme+Chat.swift +++ b/GliaWidgets/Sources/Theme/Theme+Chat.swift @@ -180,7 +180,7 @@ extension Theme { accessibility: .init(isFontScalingEnabled: true) ) let operatorImageFile = ChatImageFileContentStyle( - backgroundColor: Color.lightGrey, + backgroundColor: color.baseNeutral, accessibility: .init( contentAccessibilityLabel: Localization.Chat.Attachment.Message.Accessibility.label, youAccessibilityPlaceholder: Localization.General.you, @@ -196,7 +196,7 @@ extension Theme { let operatorMessage = OperatorMessageStyle( text: operatorText, background: .init( - background: .fill(color: Color.lightGrey), + background: .fill(color: color.baseNeutral), borderColor: .clear, borderWidth: .zero, cornerRadius: 8.49 @@ -219,7 +219,7 @@ extension Theme { ) ) let choiceCardOptionNormalState = Button( - background: .fill(color: Color.lightGrey), + background: .fill(color: color.baseNeutral), title: .init( color: color.baseDark.hex, font: font.bodyText, @@ -233,7 +233,7 @@ extension Theme { ) ) let choiceCardOptionSelectedState = Button( - background: .fill(color: Color.primary), + background: .fill(color: color.primary), title: .init( color: color.baseLight.hex, font: font.bodyText, @@ -247,16 +247,16 @@ extension Theme { ) ) let choiceCardOptionDisabledState = Button( - background: .fill(color: Color.lightGrey), + background: .fill(color: color.baseNeutral), title: .init( - color: Color.grey.hex, + color: color.baseShade.hex, font: font.bodyText, textStyle: .body, accessibility: .init(isFontScalingEnabled: true) ), cornerRadius: 4, borderWidth: 1, - borderColor: Color.baseShade.toRGBAHex(), + borderColor: color.baseShade.toRGBAHex(), accessibility: .init( label: Localization.Chat.ChoiceCard.Button.Disabled.Accessibility.label, isFontScalingEnabled: true @@ -305,7 +305,7 @@ extension Theme { placeholderFont: font.bodyText, placeholderColor: color.baseNormal, separatorColor: color.baseShade, - backgroundColor: color.background, + backgroundColor: color.baseLight, mediaButton: mediaButton, sendButton: sendButton, uploadList: uploadListStyle, @@ -372,14 +372,14 @@ extension Theme { title: Localization.Chat.unreadMessageDivider, titleColor: Color.baseNormal, titleFont: font.buttonLabel, - lineColor: Color.primary, + lineColor: color.primary, accessibility: .init(isFontScalingEnabled: true) ) let systemMessage = SystemMessageStyle( text: operatorText, background: Theme.Layer( - background: .fill(color: Color.lightGrey), + background: .fill(color: color.baseNeutral), borderColor: .clear, borderWidth: .zero, cornerRadius: 8.49 @@ -391,7 +391,7 @@ extension Theme { return ChatStyle( header: header, connect: connect, - backgroundColor: .fill(color: color.background), + backgroundColor: .fill(color: color.baseLight), preferredStatusBarStyle: .lightContent, title: Localization.Engagement.Chat.title, visitorMessageStyle: visitorMessage, @@ -424,7 +424,7 @@ extension Theme { errorIcon: Asset.uploadError.image, errorIconColor: color.systemNegative, backgroundColor: color.primary, - errorBackgroundColor: Color.lightGrey, + errorBackgroundColor: color.baseNeutral, accessibility: .init(isFontScalingEnabled: true) ) let uploading = FileUploadStateStyle( @@ -460,7 +460,7 @@ extension Theme { error: error, progressColor: color.primary, errorProgressColor: color.systemNegative, - progressBackgroundColor: Color.lightGrey, + progressBackgroundColor: color.baseNeutral, removeButtonImage: Asset.uploadRemove.image, removeButtonColor: color.baseNormal, accessibility: .init( @@ -481,7 +481,7 @@ extension Theme { errorIcon: Asset.uploadError.image, errorIconColor: color.systemNegative, backgroundColor: color.primary, - errorBackgroundColor: Color.lightGrey, + errorBackgroundColor: color.baseNeutral, accessibility: .init(isFontScalingEnabled: true) ) let download = ChatFileDownloadStateStyle( @@ -527,9 +527,9 @@ extension Theme { error: error, progressColor: color.primary, errorProgressColor: color.systemNegative, - progressBackgroundColor: Color.lightGrey, + progressBackgroundColor: color.baseNeutral, backgroundColor: .white, - borderColor: Color.lightGrey, + borderColor: color.baseNeutral, accessibility: .init( contentAccessibilityLabel: Localization.Chat.Attachment.Message.Accessibility.label, youAccessibilityPlaceholder: Localization.General.you, @@ -580,7 +580,7 @@ extension Theme { return AttachmentSourceListStyle( items: [pickPhoto, takePhoto, browse], separatorColor: color.baseShade, - backgroundColor: Color.lightGrey + backgroundColor: color.baseNeutral ) } } diff --git a/GliaWidgets/Sources/Theme/Theme+Gva.swift b/GliaWidgets/Sources/Theme/Theme+Gva.swift index 789ffc1cd..6f7fd7e70 100644 --- a/GliaWidgets/Sources/Theme/Theme+Gva.swift +++ b/GliaWidgets/Sources/Theme/Theme+Gva.swift @@ -20,14 +20,14 @@ extension Theme { ), accessibility: .init(isFontScalingEnabled: true) ), - backgroundColor: .fill(color: color.lightGrey), + backgroundColor: .fill(color: color.baseNeutral), cornerRadius: 10, borderWidth: 0, borderColor: .clear, button: .init( textFont: font.caption, - textColor: .black, - backgroundColor: .fill(color: color.background), + textColor: color.baseDark, + backgroundColor: .fill(color: color.baseLight), cornerRadius: 5, borderColor: .clear, borderWidth: 0, @@ -37,16 +37,16 @@ extension Theme { let quickReplyButton: GvaQuickReplyButtonStyle = .init( textFont: font.buttonLabel, - textColor: Color.primary, - backgroundColor: .fill(color: Color.baseLight), + textColor: color.primary, + backgroundColor: .fill(color: color.baseLight), cornerRadius: 10, - borderColor: Color.primary, + borderColor: color.primary, borderWidth: 1 ) let galleryCard: GvaGalleryCardStyle = .init( cardContainer: .init( - backgroundColor: .fill(color: color.lightGrey), + backgroundColor: .fill(color: color.baseNeutral), cornerRadius: 8, borderColor: .clear, borderWidth: 0 @@ -59,22 +59,22 @@ extension Theme { ), title: .init( font: font.mediumSubtitle1, - textColor: .black, + textColor: color.baseDark, textStyle: .body ), subtitle: .init( font: font.caption, - textColor: .black, + textColor: color.baseDark, textStyle: .caption1 ), button: .init( title: .init( font: font.caption, - textColor: .black, + textColor: color.baseDark, textStyle: .caption1 ), background: .init( - backgroundColor: .fill(color: color.background), + backgroundColor: .fill(color: color.baseLight), cornerRadius: 8, borderColor: .clear, borderWidth: 0 diff --git a/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift b/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift index a07dcbc8a..aff09be1e 100644 --- a/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift +++ b/GliaWidgets/Sources/Theme/Theme+VisitorCode.swift @@ -3,8 +3,8 @@ import UIKit extension Theme { var visitorCodeStyle: VisitorCodeStyle { let numberSlot = NumberSlotStyle( - backgroundColor: .fill(color: color.background), - borderColor: UIColor.ultraLightGray, + backgroundColor: .fill(color: color.baseLight), + borderColor: color.baseNeutral, borderWidth: 1, cornerRadius: 8, numberFont: font.header1, @@ -31,7 +31,7 @@ extension Theme { poweredBy: poweredBy, numberSlot: numberSlot, actionButton: actionButton, - backgroundColor: .fill(color: color.background), + backgroundColor: .fill(color: color.baseLight), cornerRadius: 30, closeButtonColor: .fill(color: color.baseNormal), loadingProgressColor: color.primary, @@ -39,7 +39,3 @@ extension Theme { ) } } - -private extension UIColor { - static let ultraLightGray = UIColor(red: 0.953, green: 0.953, blue: 0.953, alpha: 1) -} diff --git a/GliaWidgets/Sources/Theme/Theme.swift b/GliaWidgets/Sources/Theme/Theme.swift index 97ce15437..dc1f06f6a 100644 --- a/GliaWidgets/Sources/Theme/Theme.swift +++ b/GliaWidgets/Sources/Theme/Theme.swift @@ -91,8 +91,8 @@ public class Theme { baseLight: config.globalColors?.baseLight.map { UIColor(hex: $0) }, baseDark: config.globalColors?.baseDark.map { UIColor(hex: $0) }, baseShade: config.globalColors?.baseShade.map { UIColor(hex: $0) }, - background: config.globalColors?.background.map { UIColor(hex: $0) }, - systemNegative: config.globalColors?.systemNegative.map { UIColor(hex: $0) } + systemNegative: config.globalColors?.systemNegative.map { UIColor(hex: $0) }, + baseNeutral: config.globalColors?.baseNeutral.map { UIColor(hex: $0) } ) ) ) diff --git a/GliaWidgets/Sources/Theme/ThemeColor.swift b/GliaWidgets/Sources/Theme/ThemeColor.swift index 59f9f351a..061a676b4 100644 --- a/GliaWidgets/Sources/Theme/ThemeColor.swift +++ b/GliaWidgets/Sources/Theme/ThemeColor.swift @@ -20,14 +20,11 @@ public struct ThemeColor { /// Base shade color. By default used as a separator color between message input area and chat, in attachment source list and as a border color in media upgrae prompts. public var baseShade: UIColor - /// Background color. By default used as a background color for chat, message input area and alerts. - public var background: UIColor - /// Negative system color. By default used as a background color for "End Engagement" button, negative action button in alerts and as file download/upload error icon, progress bar and text color. public var systemNegative: UIColor /// Light grey color. By default used as a background for gva persistent buttons and gallery cards. - public var lightGrey: UIColor + public var baseNeutral: UIColor /// /// - Parameters: @@ -37,7 +34,6 @@ public struct ThemeColor { /// - baseLight: Base light color. By default used as a text color in chat/call view title, visitor chat message, "End Engagement" button, queue/connection views and operator name in calls, alert titles and some other labels. /// - baseDark: Base dark color. By default used as a text color in chat queue/connect views, operator chat messages, choice cards, message entry area, upgrade prompts, attachment source list and some other labels. /// - baseShade: Base shade color. By default used as a separator color between message input area and chat, in attachment source list and as a border color in media upgrae prompts. - /// - background: Background color. By default used as a background color for chat, message input area and alerts. /// - systemNegative: Negative system color. By default used as a background color for "End Engagement" button, negative action button in alerts and as file download/upload error icon, progress bar and text color. public init( primary: UIColor? = nil, @@ -46,9 +42,8 @@ public struct ThemeColor { baseLight: UIColor? = nil, baseDark: UIColor? = nil, baseShade: UIColor? = nil, - background: UIColor? = nil, systemNegative: UIColor? = nil, - lightGrey: UIColor? = nil + baseNeutral: UIColor? = nil ) { self.primary = primary ?? Color.primary self.secondary = secondary ?? Color.secondary @@ -56,8 +51,7 @@ public struct ThemeColor { self.baseLight = baseLight ?? Color.baseLight self.baseDark = baseDark ?? Color.baseDark self.baseShade = baseShade ?? Color.baseShade - self.background = background ?? Color.background self.systemNegative = systemNegative ?? Color.systemNegative - self.lightGrey = lightGrey ?? Color.lightGrey + self.baseNeutral = baseNeutral ?? Color.baseNeutral } } diff --git a/TestingApp/Settings/SettingsViewController.swift b/TestingApp/Settings/SettingsViewController.swift index 0cfdd1eaa..f09d123ac 100644 --- a/TestingApp/Settings/SettingsViewController.swift +++ b/TestingApp/Settings/SettingsViewController.swift @@ -186,7 +186,7 @@ private extension SettingsViewController { ) backgroundColorCell = SettingsColorCell( title: "Background:", - color: props.theme.color.background + color: props.theme.color.baseLight ) systemNegativeColorCell = SettingsColorCell( title: "System negative:", @@ -316,7 +316,6 @@ private extension SettingsViewController { baseLight: baseLightColorCell.color, baseDark: baseDarkColorCell.color, baseShade: baseShadeColorCell.color, - background: backgroundColorCell.color, systemNegative: systemNegativeColorCell.color ) let font = ThemeFont( From a9389e879a9fba46f0f33190af6ea80e9458c411 Mon Sep 17 00:00:00 2001 From: Rasmus Tauts Date: Thu, 5 Oct 2023 14:42:22 +0300 Subject: [PATCH 24/40] Fix accessiblity identifier for confirmation button This PR fixes the identifier that lead to acceptance tests to fail --- .../Confirmation/SecureConversations.ConfirmationView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift index d15265e26..11ef19a27 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift @@ -80,7 +80,7 @@ private extension SecureConversations.ConfirmationViewSwiftUI { .background(SwiftUI.Color(model.style.checkMessagesButtonStyle.backgroundColor)) .cornerRadius(4) } - .migrationAccessibilityIdentifier("secureConversations_confirmationCheckMessages_button") + .migrationAccessibilityIdentifier("secureConversations_welcomeCheckMessages_button") .migrationAccessibilityLabel(model.style.checkMessagesButtonStyle.accessibility.label) .migrationAccessibilityHint(model.style.checkMessagesButtonStyle.accessibility.hint) } From b8181e50d128228c8284b4091e9605d8fe20b31f Mon Sep 17 00:00:00 2001 From: Igor Kravchenko Date: Fri, 6 Oct 2023 11:36:36 +0300 Subject: [PATCH 25/40] Change accessibility identifier for check messages back Change accessibility identifier for check messages back to expected name on Confirmation screen. --- .../Confirmation/SecureConversations.ConfirmationView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift index 11ef19a27..d15265e26 100644 --- a/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift +++ b/GliaWidgets/SecureConversations/Confirmation/SecureConversations.ConfirmationView.swift @@ -80,7 +80,7 @@ private extension SecureConversations.ConfirmationViewSwiftUI { .background(SwiftUI.Color(model.style.checkMessagesButtonStyle.backgroundColor)) .cornerRadius(4) } - .migrationAccessibilityIdentifier("secureConversations_welcomeCheckMessages_button") + .migrationAccessibilityIdentifier("secureConversations_confirmationCheckMessages_button") .migrationAccessibilityLabel(model.style.checkMessagesButtonStyle.accessibility.label) .migrationAccessibilityHint(model.style.checkMessagesButtonStyle.accessibility.hint) } From 40bb97fe95a799fba6aa7bfaad21402dd321636a Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Wed, 11 Oct 2023 11:47:27 +0300 Subject: [PATCH 26/40] Add powered by to leave queue alert This commit syncs the leave queue alert to how Android works. Also, the end engagement alert now uses the `showsPoweredBy` variable. This means that it will now respect the global setting rather than always setting it as yes. This would bring issues if a client pays for hiding powered by, as it would be wrongly shown in that case. MOB-2742 --- GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift index 61b226442..065e36b8d 100644 --- a/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift +++ b/GliaWidgets/Sources/Theme/Theme+AlertConfiguration.swift @@ -6,7 +6,7 @@ extension Theme { negativeTitle: Localization.General.no, positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, - showsPoweredBy: false + showsPoweredBy: showsPoweredBy ) let endEngagement = ConfirmationAlertConfiguration( title: Localization.Engagement.End.Confirmation.header, @@ -14,7 +14,7 @@ extension Theme { negativeTitle: Localization.General.no, positiveTitle: Localization.General.yes, switchButtonBackgroundColors: true, - showsPoweredBy: true + showsPoweredBy: showsPoweredBy ) let operatorEndedEngagement = SingleActionAlertConfiguration( title: Localization.Engagement.Ended.header, From 4ad138001104ab735af6766e9bca7016bf48b5b1 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Wed, 11 Oct 2023 12:58:23 +0300 Subject: [PATCH 27/40] Fix visitor code spinner animation The `isRemovedOnCompletion` property was missing, which meant that the animation never ran, and the spinner was always static. Now the animation runs forever until removed. MOB-2743 --- .../Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift b/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift index afcdb5cc4..7d06a243a 100644 --- a/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift +++ b/GliaWidgets/Sources/CallVisualizer/VisitorCode/VisitorCodeView.swift @@ -227,6 +227,7 @@ extension CallVisualizer { rotation.toValue = CGFloat.pi * 2 rotation.duration = 1.0 rotation.repeatCount = Float.infinity + rotation.isRemovedOnCompletion = false spinnerView.tintColor = props.style.loadingProgressColor spinnerView.layer.add(rotation, forKey: "Spin") } From b3ef1e68d7466e3a099ab63acccb2ee868522b07 Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Tue, 10 Oct 2023 15:28:54 +0300 Subject: [PATCH 28/40] Change priority of company name algorithm Before, the UiTheme took the highest priority in the algorithm to determine the company name. Now the remote company name has the highest priority, with the added constraint that it cannot be empty, as this will be the default value on the default locale. In case it is empty, the UiTheme will come afterwards, then the SDK configuration, and finally the local fallback. MOB-2733 --- .../Public/Glia/Glia+StartEngagement.swift | 23 +++++----- .../Glia/GliaTests+StartEngagement.swift | 46 ++++++++++++++++++- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift index d37f65e1c..c6e4f1566 100644 --- a/GliaWidgets/Public/Glia/Glia+StartEngagement.swift +++ b/GliaWidgets/Public/Glia/Glia+StartEngagement.swift @@ -48,12 +48,12 @@ extension Glia { theme.chat.connect.queue.firstText = companyName( using: interactor, - currentName: theme.chat.connect.queue.firstText + themeCompanyName: theme.chat.connect.queue.firstText ) theme.call.connect.queue.firstText = companyName( using: interactor, - currentName: theme.call.connect.queue.firstText + themeCompanyName: theme.call.connect.queue.firstText ) let viewFactory = ViewFactory( @@ -81,20 +81,21 @@ extension Glia { func companyName( using interactor: Interactor, - currentName: String? + themeCompanyName: String? ) -> String { - // As the default value is empty, it means that the integrator - // has set a value on the theme itself. Return that same value. - if let currentName, !currentName.isEmpty { - return currentName - } - let companyNameStringKey = "general.company_name" - // Company name has been set on the custom locale. - if let remoteCompanyName = stringProviding?.getRemoteString(companyNameStringKey) { + // Company name has been set on the custom locale and is not empty. + if let remoteCompanyName = stringProviding?.getRemoteString(companyNameStringKey), + !remoteCompanyName.isEmpty { return remoteCompanyName } + // As the default value in the theme is not empty, it means that + // the integrator has set a value on the theme itself. Return that + // same value. + else if let themeCompanyName, !themeCompanyName.isEmpty { + return themeCompanyName + } // Integrator has not set a company name in the custom locale, // but has set it on the configuration. else if !interactor.configuration.companyName.isEmpty { diff --git a/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift b/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift index 573aa7e1b..0bcafdf2a 100644 --- a/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift +++ b/GliaWidgetsTests/Sources/Glia/GliaTests+StartEngagement.swift @@ -111,8 +111,13 @@ extension GliaTests { let sdk = Glia(environment: environment) + // Even if theme is set, the remote string takes priority. + let theme = Theme() + theme.call.connect.queue.firstText = "Glia 1" + theme.chat.connect.queue.firstText = "Glia 2" + try sdk.configure(with: .mock()) { } - try sdk.startEngagement(engagementKind: .chat, in: ["queueId"]) + try sdk.startEngagement(engagementKind: .chat, in: ["queueId"], theme: theme) let configuredSdkTheme = resultingViewFactory?.theme XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Glia") @@ -174,4 +179,43 @@ extension GliaTests { XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Company Name") XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "Company Name") } + + func testCompanyNameIsReceivedFromThemeIfCustomLocalesIsEmpty() throws { + var environment = Glia.Environment.failing + var resultingViewFactory: ViewFactory? + + environment.createRootCoordinator = { _, viewFactory, _, _, _, _, _ in + resultingViewFactory = viewFactory + + return .mock( + interactor: .mock(environment: .failing), + viewFactory: viewFactory, + sceneProvider: nil, + engagementKind: .none, + screenShareHandler: .mock, + features: [], + environment: .failing + ) + } + + environment.coreSdk.localeProvider.getRemoteString = { _ in "" } + environment.coreSdk.configureWithInteractor = { _ in } + environment.coreSdk.configureWithConfiguration = { _, completion in + completion?() + } + environment.coreSdk.getCurrentEngagement = { nil } + + let sdk = Glia(environment: environment) + + let theme = Theme() + theme.call.connect.queue.firstText = "Glia 1" + theme.chat.connect.queue.firstText = "Glia 2" + + try sdk.configure(with: .mock()) + try sdk.startEngagement(engagementKind: .chat, in: ["queueId"], theme: theme) + + let configuredSdkTheme = resultingViewFactory?.theme + XCTAssertEqual(configuredSdkTheme?.call.connect.queue.firstText, "Glia 1") + XCTAssertEqual(configuredSdkTheme?.chat.connect.queue.firstText, "Glia 2") + } } From a4a15a2c1af261391b22135473a2a04a8a2c2cc1 Mon Sep 17 00:00:00 2001 From: Mikk Tamme <98313091+mikktammeglia@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:41:07 +0300 Subject: [PATCH 29/40] Adding of PR template (#792) As discussed in retrospective. --- .github/PULL_REQUEST_TEMPLATE.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..bcafef811 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +**Jira issue:** +https://glia.atlassian.net/browse/MOB-xxx + +**What was solved?** + +**Release notes:** + + - [ ] Feature + - [ ] Ignore + - [ ] Release notes (Is it clear from the description here?) + - [ ] Migration guide (If changes are needed for integrator already using the SDK - what needs to be communicated? Add underneath please) + +**Additional info:** + + - [ ] Tests fixed, added? Unit, acceptance, snapshots? + - [ ] Logging necessary for future troubleshooting of customer issues added? + +**Screenshots:** From 56b6c5f8d6d5da0808855ccca20fe1c8bf1d18bd Mon Sep 17 00:00:00 2001 From: Igor Kravchenko Date: Wed, 11 Oct 2023 16:59:55 +0300 Subject: [PATCH 30/40] Update GliaCoreSDK to 1.1.4 and remove GliaWidgetsXcf Update GliaCoreSDK to 1.1.4 and remove GliaWidgetsXcf. --- GliaWidgets.podspec | 2 +- Package.swift | 23 ++--------------------- Podfile.lock | 4 ++-- templates/GliaWidgets.podspec | 2 +- templates/Package.swift | 19 ------------------- 5 files changed, 6 insertions(+), 44 deletions(-) diff --git a/GliaWidgets.podspec b/GliaWidgets.podspec index 96244e430..6e80be0b0 100644 --- a/GliaWidgets.podspec +++ b/GliaWidgets.podspec @@ -19,5 +19,5 @@ Pod::Spec.new do |s| } s.exclude_files = ['GliaWidgets/Window/**'] - s.dependency 'GliaCoreSDK', '1.1.3' + s.dependency 'GliaCoreSDK', '1.1.4' end diff --git a/Package.swift b/Package.swift index ebfe359df..fee404414 100644 --- a/Package.swift +++ b/Package.swift @@ -11,10 +11,6 @@ let package = Package( .library( name: "GliaWidgets", targets: ["GliaWidgetsSDK"] - ), - .library( - name: "GliaWidgets-xcframework", - targets: ["GliaWidgetsSDK-xcframework"] ) ], targets: [ @@ -35,13 +31,8 @@ let package = Package( ), .binaryTarget( name: "GliaCoreSDK", - url: "https://github.com/salemove/ios-bundle/releases/download/1.1.3/GliaCoreSDK.xcframework.zip", - checksum: "ffffc1a4bdbf467b076823d604cf8a628c78fd49a7ceda6dd423f569a13c5fa3" - ), - .binaryTarget( - name: "GliaWidgetsXcf", - url: "https://github.com/salemove/ios-sdk-widgets/releases/download/2.0.6/GliaWidgetsXcf.xcframework.zip", - checksum: "27dd290835cc21e8191d16d128c8b4d19a7bda8f34029821626eefd91a7c448b" + url: "https://github.com/salemove/ios-bundle/releases/download/1.1.4/GliaCoreSDK.xcframework.zip", + checksum: "cc06b73535b6cbbc2e0cc27c3571368cb1a021ca5485eb907e7cf9581696f0bb" ), .target( name: "GliaWidgets", @@ -64,16 +55,6 @@ let package = Package( "WebRTC", "GliaWidgets" ] - ), - .target( - name: "GliaWidgetsSDK-xcframework", - dependencies: [ - "GliaCoreSDK", - "GliaWidgetsXcf", - "GliaCoreDependency", - "TwilioVoice", - "WebRTC" - ] ) ] ) diff --git a/Podfile.lock b/Podfile.lock index 9d6242913..a5ff2b4ba 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -7,7 +7,7 @@ PODS: - AccessibilitySnapshot/Core - SnapshotTesting (~> 1.0) - GliaCoreDependency (1.2) - - GliaCoreSDK (1.1.3): + - GliaCoreSDK (1.1.4): - GliaCoreDependency (= 1.2) - TwilioVoice (= 6.3.1) - WebRTC-lib (= 96.0.0) @@ -34,7 +34,7 @@ SPEC REPOS: SPEC CHECKSUMS: AccessibilitySnapshot: a91e4a69f870188b51f43863d9fc7269d07cdd93 GliaCoreDependency: 87b3897f0d85321ecf77f1faa829211ad527e54d - GliaCoreSDK: cae2181c8d19f39609c727a8c2a2268e256f5746 + GliaCoreSDK: 94a986c0a0eae705a9abb763bc4c4fcb01f9b013 SnapshotTesting: 6141c48b6aa76ead61431ca665c14ab9a066c53b SwiftLint: 13280e21cdda6786ad908dc6e416afe5acd1fcb7 TwilioVoice: 098a959181d4607921f5822d3c9f13043ea4075b diff --git a/templates/GliaWidgets.podspec b/templates/GliaWidgets.podspec index 9f82b74fb..6bd36e2ca 100644 --- a/templates/GliaWidgets.podspec +++ b/templates/GliaWidgets.podspec @@ -19,5 +19,5 @@ Pod::Spec.new do |s| } s.exclude_files = ['GliaWidgets/Window/**'] - s.dependency 'GliaCoreSDK', '1.1.3' + s.dependency 'GliaCoreSDK', '1.1.4' end diff --git a/templates/Package.swift b/templates/Package.swift index c094d78a2..e1d9a72c8 100644 --- a/templates/Package.swift +++ b/templates/Package.swift @@ -11,10 +11,6 @@ let package = Package( .library( name: "GliaWidgets", targets: ["GliaWidgetsSDK"] - ), - .library( - name: "GliaWidgets-xcframework", - targets: ["GliaWidgetsSDK-xcframework"] ) ], targets: [ @@ -38,11 +34,6 @@ let package = Package( url: "https://github.com/salemove/ios-bundle/releases/download/${CORE_SDK_VERSION}/GliaCoreSDK.xcframework.zip", checksum: "${CORE_SDK_CHECKSUM}" ), - .binaryTarget( - name: "GliaWidgetsXcf", - url: "https://github.com/salemove/ios-sdk-widgets/releases/download/2.0.1/GliaWidgetsXcf.xcframework.zip", - checksum: "26f6e0bc6e32f4223f635d8de8aa4877338aed7a323f2127a05980f347ac1f9a" - ), .target( name: "GliaWidgets", path: "GliaWidgets", @@ -64,16 +55,6 @@ let package = Package( "WebRTC", "GliaWidgets" ] - ), - .target( - name: "GliaWidgetsSDK-xcframework", - dependencies: [ - "GliaCoreSDK", - "GliaWidgetsXcf", - "GliaCoreDependency", - "TwilioVoice", - "WebRTC" - ] ) ] ) From c2c70127784df08611c583ad50551f36febda767 Mon Sep 17 00:00:00 2001 From: Egor Egorov Date: Wed, 11 Oct 2023 15:16:29 +0300 Subject: [PATCH 31/40] Connecting state issue fixes On SDK configuration, interactor instance is created and has .none state. When Call screen is loaded, its start() method is called which executes some updates based on current interactor.state. When configure method is called before each engagement start (like we currently do in WidgetsSDK Testing app), CallViewModel.start() does nothing, because interactor.state is .none. But when WidgesSDK is configured once (for example on the app launch), the same interactor instance is used for all subsequent engagements. When you end first engagement (Chat/Audio/Video, probably CV also), interactor.state is .ended. Then if you start new Audio/Video engagement, CallViewModel.start() calls CallViewModel.call.end() method, which breaks something and connecting state becomes infinite. This commit fixes calling CallViewModel.call.end() on Audio/Video engagement start. Commit also make two engagement references weak to avoid retaining it when CoreSDK already released it from memory. The toggle (UISwitch) was added to Main screen, that provides the ability to disable/enable SDK configuration before each engagement. MOB-2730 --- .../ViewModel/Call/CallViewModel.swift | 15 +++++- .../ViewModel/EngagementViewModel.swift | 10 ++-- .../Sources/CallViewModelTests.swift | 12 +++++ TestingApp/Main.storyboard | 50 ++++++++++++------- .../ViewController/ViewController.swift | 47 ++++++++++++----- 5 files changed, 99 insertions(+), 35 deletions(-) diff --git a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift index ec2f08e4d..86a705cb5 100644 --- a/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/Call/CallViewModel.swift @@ -72,7 +72,20 @@ class CallViewModel: EngagementViewModel, ViewModel { super.start() update(for: call.kind.value) - update(for: interactor.state) + + // In the case when SDK is configured once and then + // visitor has several Audio/Video engagements in a raw, + // after ending each of them, `interactor.state` has `.ended` value, + // which causes calling `call.end()` on the start of the next + // Audio/Video engagement. That `call.end()` breaks the flow and SDK does not + // handle `connected` state properly. So we need to skip handling `.ended` state + // on the start of a new engagement. + switch interactor.state { + case .ended: + break + default: + update(for: interactor.state) + } switch startWith { case .engagement(let mediaType): diff --git a/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift b/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift index e1e615749..26e843a84 100644 --- a/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift +++ b/GliaWidgets/Sources/ViewModel/EngagementViewModel.swift @@ -11,6 +11,8 @@ class EngagementViewModel: CommonEngagementModel { let alertConfiguration: AlertConfiguration let environment: Environment let screenShareHandler: ScreenShareHandler + // Need to keep strong reference of `activeEngagement`, + // to be able to fetch survey after ending engagement var activeEngagement: CoreSdkClient.Engagement? private(set) var isViewActive = ObservableValue(with: false) @@ -225,10 +227,10 @@ class EngagementViewModel: CommonEngagementModel { } func endSession() { - interactor.endSession { - self.engagementDelegate?(.finished) - } failure: { _ in - self.engagementDelegate?(.finished) + interactor.endSession { [weak self] in + self?.engagementDelegate?(.finished) + } failure: { [weak self] _ in + self?.engagementDelegate?(.finished) } self.screenShareHandler.stop(nil) } diff --git a/GliaWidgetsTests/Sources/CallViewModelTests.swift b/GliaWidgetsTests/Sources/CallViewModelTests.swift index b3500afff..68b97d7e4 100644 --- a/GliaWidgetsTests/Sources/CallViewModelTests.swift +++ b/GliaWidgetsTests/Sources/CallViewModelTests.swift @@ -335,4 +335,16 @@ class CallViewModelTests: XCTestCase { XCTAssertEqual(call.kind.value, .audio) } + + func test_startMethodDoesNotHandleInteractorStateEnded() { + let interactor: Interactor = .mock() + interactor.state = .ended(.byOperator) + let call: Call = .mock() + let viewModel: CallViewModel = .mock(interactor: interactor, call: call) + + XCTAssertEqual(call.state.value, .none) + viewModel.start() + + XCTAssertEqual(call.state.value, .none) + } } diff --git a/TestingApp/Main.storyboard b/TestingApp/Main.storyboard index f573b303d..dea23e613 100644 --- a/TestingApp/Main.storyboard +++ b/TestingApp/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -21,7 +21,7 @@ - + + + + + + + + + + + - + - +