Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entry widget and secure conversations v2 #1036

Draft
wants to merge 84 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
a828cdf
Update dependencies declared in `Podfile` and `Package.swift`
Nov 11, 2024
f961b4c
Add EntryWidget UI
rasmustautsglia Sep 23, 2024
23e2133
Add Engagement Launcher interface and getter from Glia
ykyivskyi-gl Sep 25, 2024
0fc6921
Add EntryWidget embedded view
rasmustautsglia Sep 26, 2024
f3a8ec2
Implement EngagementLauncher logic
ykyivskyi-gl Sep 30, 2024
c7af051
Add Unified Customization to EntryWidget
rasmustautsglia Oct 3, 2024
30749bd
Update Entry Widget media types texts
rasmustautsglia Oct 8, 2024
a57c3b6
Implement QueuesMonitor to observe queues' engagement type updates
ykyivskyi-gl Oct 8, 2024
f57a1f7
Add remote configuration for secure conversations
igorkravchenko Oct 11, 2024
7a18b57
Integrate queues monitor and engagement launcher into EntryWidget
ykyivskyi-gl Oct 13, 2024
63eac40
Add new localization keys and update existing for local strings for SC
igorkravchenko Oct 14, 2024
f72b3fa
Make entry widget height dynamic
rasmustautsglia Oct 16, 2024
4450a35
Update 'Check Messages' button and margins on SC Welcome screen
igorkravchenko Oct 15, 2024
412fb70
Add new public interfaces to the Entry Widget
rasmustautsglia Oct 18, 2024
67e90a7
Cover QueuesMonitor with unit tests
ykyivskyi-gl Oct 18, 2024
ed9d257
Add new localizations for the Entry Widget.
AH-MOC Oct 16, 2024
2b998e7
Add Entry Widget Loading view design
rasmustautsglia Oct 21, 2024
edd35cf
Introduce SC bottom banner UI on chat screen
igorkravchenko Oct 21, 2024
26f06ee
Implement unified customization for SC bottom banner
igorkravchenko Oct 23, 2024
ffac050
Make passed getEngagementLauncher queuesId paramater non-nullable
ykyivskyi-gl Oct 24, 2024
cc26379
Leave Current Conversation dialog UI
Oct 25, 2024
309f512
Remote config for Leave Current Conversation dialog
Oct 25, 2024
5df2e7d
Hide the "Secure Messaging" if visitor is not authenticated
rasmustautsglia Oct 24, 2024
1c404a6
Snapshot tests for Leave Current Conversation dialog
Oct 25, 2024
f5d277f
Add accessibility modifiers to the Entry Widget
AH-MOC Oct 22, 2024
ddab344
Add new send message unavailability banner
igorkravchenko Oct 24, 2024
f00994e
Add unified customization for new SC unavailability indicator for chat
igorkravchenko Oct 26, 2024
b3a7c88
Make EntryWidget sheet landscape adaptable
rasmustautsglia Oct 28, 2024
7695def
Replace unavailability dialog with banner view on Transcript screen
igorkravchenko Oct 28, 2024
efbbfdf
Toggle SC bottom banner visibility based on view model
igorkravchenko Oct 29, 2024
2a2ab74
Use queues from QueuesMonitor to determine Secure Conversations avail…
ykyivskyi-gl Oct 30, 2024
823b641
Improve the Entry Widget Style structures
AH-MOC Oct 28, 2024
6936c3d
Hide EntryWidget sheet before engagement
rasmustautsglia Nov 4, 2024
e73c33f
Add snapshot tests to EntryWidget
rasmustautsglia Nov 1, 2024
0c01175
Remove rebasing issue
rasmustautsglia Nov 5, 2024
72e4174
Optimize using of strings for the Entry Widget
AH-MOC Nov 4, 2024
a611172
Introduce disabled state for ChatMessageEntry style
igorkravchenko Nov 2, 2024
4542439
Bump up deployment target from iOS 13 to 14
AH-MOC Nov 6, 2024
bda2891
Introduce disabled state for file upload list
igorkravchenko Nov 7, 2024
577f9a2
Update dependencies declared in `Podfile` and `Package.swift`
Nov 12, 2024
161004d
Disable send message and pick media buttons instead of hiding them
igorkravchenko Nov 11, 2024
4468354
Chat to Secure Conversation transfer
Nov 8, 2024
0b7b6e2
Add SC unread message badge on Entry Widget
ykyivskyi-gl Nov 11, 2024
aec5452
Add logs and telemetry for Entry Widget
rasmustautsglia Nov 12, 2024
8070d14
Update default global colors according to color palette
igorkravchenko Oct 22, 2024
4f0858e
Remove deprecated and existing startEngagement methods
ykyivskyi-gl Nov 14, 2024
9b1c593
Fix remote configuration not being applied to Entry Widget
rasmustautsglia Nov 15, 2024
6c8253a
Change Chat Button label in EntryWidget
rasmustautsglia Nov 13, 2024
d95f1fb
SecureConversation business logic
Nov 18, 2024
1dc3644
Add disabled unified customization for disabled state for chat messag…
AH-MOC Nov 15, 2024
29af2eb
Add snapshot tests for bottom banner
igorkravchenko Nov 19, 2024
c7274e4
Add entry point for EntryWidget for Secure Conversation
ykyivskyi-gl Nov 20, 2024
1bbb574
ViewController refactoring
Nov 20, 2024
c3b52e2
Add pending secure messaging logic to EntryWidget
Nov 19, 2024
3d32958
Apply Unified UI for the SC
AH-MOC Nov 20, 2024
c56c4b6
Change subheadline color In EntryWidget
rasmustautsglia Nov 20, 2024
b20cbba
Extend SCv2 logic with unreadMessageCount
Nov 25, 2024
2acb245
Add accessibility identifiers to Entry Widget items
AH-MOC Nov 25, 2024
0f62173
Bump up Core SDK version to 2.0.2 and update SC interface
igorkravchenko Nov 27, 2024
9f2c237
Show Entry Widget on SC top banner click
ykyivskyi-gl Nov 26, 2024
29346ee
Add Unit and Snapshot tests for top banner on Secure Conversations
ykyivskyi-gl Nov 28, 2024
fa498eb
Fix memory leak in Chat module
Nov 28, 2024
44a9287
Apply unified UI for SC's top banner on ChatView
ykyivskyi-gl Nov 29, 2024
64044bb
Isolate pending interaction logic in separate model
igorkravchenko Nov 29, 2024
0c04e8f
Fix strict version in Podfile.lock
Dec 6, 2024
002ebe0
Improve mark as read SC messages
ykyivskyi-gl Dec 5, 2024
63043ff
Address unavailability banner showing up for SC flow
igorkravchenko Dec 5, 2024
d8d226b
Update SC availability taking into account 'transferring' state
igorkravchenko Dec 5, 2024
53122a2
Create PendingInteraction model after configuration
igorkravchenko Dec 11, 2024
1b0e74f
Update dependencies declared in `Podfile` and `Package.swift`
Dec 13, 2024
2161129
Handle ongoing engagement in EntryWidget
rasmustautsglia Dec 6, 2024
6c89aac
Create interface for resuming call visualizer
rasmustautsglia Dec 17, 2024
2714cf7
Add a state property to determine resume behavior
rasmustautsglia Dec 19, 2024
9afcf2a
Fill area under message entry with same bg color as message entry
igorkravchenko Dec 19, 2024
9e35c62
Handle `follow_up` end reason
Dec 23, 2024
4c72685
Fix keeping wrong interactor state after CV engagement
Dec 23, 2024
a0ef66e
Fix handling engagement ended flow
Dec 24, 2024
7ad0d5b
Add tests for Interactor state updates on engagement end
ykyivskyi-gl Dec 30, 2024
25d2a27
Remove bubble related toggles from initial screen in TestingApp
Dec 30, 2024
cb7f693
Update image preview screen logs to align with Android
ykyivskyi-gl Jan 2, 2025
e332c67
Mark deprecated styles as unavailable
Dec 31, 2024
ff6d049
Log ongoing engagement event in Entry Widget
rasmustautsglia Dec 31, 2024
30056c6
Add snapshot tests for SC's unified UI
ykyivskyi-gl Jan 7, 2025
c77ae69
Do not cancel enqueuing if new enqueue is the same engagement type
rasmustautsglia Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions GliaWidgets.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Pod::Spec.new do |s|
s.source = { :git => 'https://github.com/salemove/ios-sdk-widgets.git', :tag => s.version.to_s }

s.module_name = 'GliaWidgets'
s.ios.deployment_target = '13.0'
s.ios.deployment_target = '14.0'
s.source_files = 'GliaWidgets/**/*.swift'
s.swift_version = '5.3'

Expand All @@ -19,5 +19,5 @@ Pod::Spec.new do |s|
}
s.exclude_files = ['GliaWidgets/Window/**']

s.dependency 'GliaCoreSDK', '1.5.9'
s.dependency 'GliaCoreSDK', '2.0.4'
end
522 changes: 454 additions & 68 deletions GliaWidgets.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions GliaWidgets/Asset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ public enum Asset {
public static let uploadRemove = ImageAsset(name: "uploadRemove")
public static let chatPickMedia = ImageAsset(name: "chatPickMedia")
public static let chatSend = ImageAsset(name: "chatSend")
public static let sendMessageUnavailableInfo = ImageAsset(name: "send-message-unavailable-info")
public static let unreadMessageIndicator = ImageAsset(name: "unreadMessageIndicator")
public static let back = ImageAsset(name: "back")
public static let close = ImageAsset(name: "close")
public static let browseIcon = ImageAsset(name: "browseIcon")
public static let cameraIcon = ImageAsset(name: "cameraIcon")
public static let chevronDownIcon = ImageAsset(name: "chevronDownIcon")
public static let photoLibraryIcon = ImageAsset(name: "photoLibraryIcon")
public static let gliaLogo = ImageAsset(name: "gliaLogo")
public static let startScreenShare = ImageAsset(name: "startScreenShare")
Expand Down Expand Up @@ -109,11 +111,13 @@ public enum Asset {
uploadRemove,
chatPickMedia,
chatSend,
sendMessageUnavailableInfo,
unreadMessageIndicator,
back,
close,
browseIcon,
cameraIcon,
chevronDownIcon,
photoLibraryIcon,
gliaLogo,
startScreenShare,
Expand Down
10 changes: 5 additions & 5 deletions GliaWidgets/Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import UIKit

enum Color {
static let primary = UIColor(hex: 0x0F6BFF) // blue
static let secondary = UIColor(hex: 0x00B233) // green
static let secondary = UIColor(hex: 0x18901C) // green
static let baseLight = UIColor(hex: 0xFFFFFF) // white
static let systemNegative = UIColor(hex: 0xD11149) // red
static let baseNormal = UIColor(hex: 0x6C7683) // grey
static let baseShade = UIColor(hex: 0x6C7683, alpha: 0.5)
static let systemNegative = UIColor(hex: 0xBC0F42) // red
static let baseNormal = UIColor(hex: 0x616A75) // gray
static let baseShade = UIColor(hex: 0xB6BBC1) // mid-gray
static let baseDark = UIColor(hex: 0x2C0735) // purple
static let baseNeutral = UIColor(hex: 0xF3F3F3) // light gray
static let baseNeutral = UIColor(hex: 0xF7F7F7) // light gray
}
142 changes: 130 additions & 12 deletions GliaWidgets/Localization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,106 @@ internal enum Localization {
internal static var message: String { Localization.tr("Localizable", "engagement.queue_wait.message", fallback: "You can continue browsing and we will connect you automatically.") }
}
internal enum SecureMessaging {
/// Messaging
internal static var title: String { Localization.tr("Localizable", "engagement.secure_messaging.title", fallback: "Messaging") }
/// Secure Messaging
internal static var title: String { Localization.tr("Localizable", "engagement.secure_messaging.title", fallback: "Secure Messaging") }
}
internal enum Video {
/// Video
internal static var title: String { Localization.tr("Localizable", "engagement.video.title", fallback: "Video") }
}
}
internal enum EntryWidget {
internal enum Audio {
internal enum Button {
/// Speak through your device
internal static var description: String { Localization.tr("Localizable", "entry_widget.audio.button.description", fallback: "Speak through your device") }
/// Audio
internal static var label: String { Localization.tr("Localizable", "entry_widget.audio.button.label", fallback: "Audio") }
internal enum Accessibility {
/// Starts a call
internal static var hint: String { Localization.tr("Localizable", "entry_widget.audio.button.accessibility.hint", fallback: "Starts a call") }
}
}
}
internal enum CallVisualizer {
/// Screen sharing in progress
internal static var desciption: String { Localization.tr("Localizable", "entry_widget.call_visualizer.desciption", fallback: "Screen sharing in progress") }
internal enum Button {
/// Call Visualizer
internal static var label: String { Localization.tr("Localizable", "entry_widget.call_visualizer.button.label", fallback: "Call Visualizer") }
}
}
internal enum EmptyState {
/// We are here to assist you during our business hours.
internal static var description: String { Localization.tr("Localizable", "entry_widget.empty_state.description", fallback: "We are here to assist you during our business hours.") }
/// Support team is currently offline
internal static var title: String { Localization.tr("Localizable", "entry_widget.empty_state.title", fallback: "Support team is currently offline") }
}
internal enum ErrorState {
/// We could not load the contacts at this time. This may be due to a temporary syncing issue or network problem.
internal static var description: String { Localization.tr("Localizable", "entry_widget.error_state.description", fallback: "We could not load the contacts at this time. This may be due to a temporary syncing issue or network problem.") }
/// Could not load the contacts
internal static var title: String { Localization.tr("Localizable", "entry_widget.error_state.title", fallback: "Could not load the contacts") }
internal enum TryAgain {
internal enum Button {
/// Try again
internal static var label: String { Localization.tr("Localizable", "entry_widget.error_state.try_again.button.label", fallback: "Try again") }
}
}
}
internal enum LiveChat {
internal enum Button {
/// For the texter in all of us
internal static var description: String { Localization.tr("Localizable", "entry_widget.live_chat.button.description", fallback: "For the texter in all of us") }
/// Chat
internal static var label: String { Localization.tr("Localizable", "entry_widget.live_chat.button.label", fallback: "Chat") }
internal enum Accessibility {
/// Starts a chat
internal static var hint: String { Localization.tr("Localizable", "entry_widget.live_chat.button.accessibility.hint", fallback: "Starts a chat") }
}
}
}
internal enum Loading {
internal enum Accessibility {
/// Loading indicator. Waiting for available options.
internal static var label: String { Localization.tr("Localizable", "entry_widget.loading.accessibility.label", fallback: "Loading indicator. Waiting for available options.") }
}
}
internal enum OngoingEngagement {
/// Ongoing • Tap to return
internal static var description: String { Localization.tr("Localizable", "entry_widget.ongoing_engagement.description", fallback: "Ongoing • Tap to return") }
internal enum Button {
internal enum Accessibility {
/// Returns to ongoing engagement
internal static var hint: String { Localization.tr("Localizable", "entry_widget.ongoing_engagement.button.accessibility.hint", fallback: "Returns to ongoing engagement") }
}
}
}
internal enum SecureMessaging {
internal enum Button {
/// Start a conversation, we’ll get back to you
internal static var description: String { Localization.tr("Localizable", "entry_widget.secure_messaging.button.description", fallback: "Start a conversation, we’ll get back to you") }
/// Secure Messaging
internal static var label: String { Localization.tr("Localizable", "entry_widget.secure_messaging.button.label", fallback: "Secure Messaging") }
internal enum Accessibility {
/// Starts messaging with us
internal static var hint: String { Localization.tr("Localizable", "entry_widget.secure_messaging.button.accessibility.hint", fallback: "Starts messaging with us") }
}
}
}
internal enum Video {
internal enum Button {
/// Face-to-face, just like in person
internal static var description: String { Localization.tr("Localizable", "entry_widget.video.button.description", fallback: "Face-to-face, just like in person") }
/// Video
internal static var label: String { Localization.tr("Localizable", "entry_widget.video.button.label", fallback: "Video") }
internal enum Accessibility {
/// Starts a video call
internal static var hint: String { Localization.tr("Localizable", "entry_widget.video.button.accessibility.hint", fallback: "Starts a video call") }
}
}
}
}
internal enum Error {
/// Something went wrong.
internal static var general: String { Localization.tr("Localizable", "error.general", fallback: "Something went wrong.") }
Expand Down Expand Up @@ -563,11 +655,11 @@ internal enum Localization {
}
}
internal enum MessageCenter {
/// Messaging
internal static var header: String { Localization.tr("Localizable", "message_center.header", fallback: "Messaging") }
/// Secure Messaging
internal static var header: String { Localization.tr("Localizable", "message_center.header", fallback: "Secure Messaging") }
internal enum Confirmation {
/// Your message has been sent. We will get back to you within 48 hours.
internal static var subtitle: String { Localization.tr("Localizable", "message_center.confirmation.subtitle", fallback: "Your message has been sent. We will get back to you within 48 hours.") }
/// Your message has been sent. We will get back to you within 1 business day.
internal static var subtitle: String { Localization.tr("Localizable", "message_center.confirmation.subtitle", fallback: "Your message has been sent. We will get back to you within 1 business day.") }
internal enum CheckMessages {
internal enum Accessibility {
/// Navigates you to the chat transcript.
Expand All @@ -592,10 +684,10 @@ internal enum Localization {
internal static var checkMessages: String { Localization.tr("Localizable", "message_center.welcome.check_messages", fallback: "Check messages") }
/// Your message
internal static var messageTitle: String { Localization.tr("Localizable", "message_center.welcome.message_title", fallback: "Your message") }
/// Send a message and we will get back to you within 48 hours.
internal static var subtitle: String { 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 var title: String { Localization.tr("Localizable", "message_center.welcome.title", fallback: "Welcome to Message Center") }
/// Send a message and we will get back to you within 1 business day.
internal static var subtitle: String { Localization.tr("Localizable", "message_center.welcome.subtitle", fallback: "Send a message and we will get back to you within 1 business day.") }
/// Welcome to Secure Messaging
internal static var title: String { Localization.tr("Localizable", "message_center.welcome.title", fallback: "Welcome to Secure Messaging") }
internal enum CheckMessages {
internal enum Accessibility {
/// Navigates you to the chat transcript.
Expand All @@ -611,8 +703,8 @@ internal enum Localization {
}
}
internal enum MessageInput {
/// Enter your message
internal static var placeholder: String { Localization.tr("Localizable", "message_center.welcome.message_input.placeholder", fallback: "Enter your message") }
/// Enter message
internal static var placeholder: String { Localization.tr("Localizable", "message_center.welcome.message_input.placeholder", fallback: "Enter message") }
}
internal enum MessageLength {
/// The message cannot exceed 10,000 characters.
Expand Down Expand Up @@ -644,6 +736,32 @@ internal enum Localization {
}
}
}
internal enum SecureMessaging {
internal enum Chat {
internal enum Banner {
/// Secure messaging has an expected response time of 1 business day.
internal static var bottom: String { Localization.tr("Localizable", "secure_messaging.chat.banner.bottom", fallback: "Secure messaging has an expected response time of 1 business day.") }
/// Need live support?
internal static var top: String { Localization.tr("Localizable", "secure_messaging.chat.banner.top", fallback: "Need live support?") }
}
internal enum LeaveCurrentConversation {
/// You have an ongoing conversation. Starting a new conversation before ongoing ones are resolved may lead to our agents overlooking your current query.
internal static var message: String { Localization.tr("Localizable", "secure_messaging.chat.leave_current_conversation.message", fallback: "You have an ongoing conversation. Starting a new conversation before ongoing ones are resolved may lead to our agents overlooking your current query.") }
/// Leave Current Conversation?
internal static var title: String { Localization.tr("Localizable", "secure_messaging.chat.leave_current_conversation.title", fallback: "Leave Current Conversation?") }
internal enum Button {
/// Leave
internal static var negative: String { Localization.tr("Localizable", "secure_messaging.chat.leave_current_conversation.button.negative", fallback: "Leave") }
/// Stay
internal static var positive: String { Localization.tr("Localizable", "secure_messaging.chat.leave_current_conversation.button.positive", fallback: "Stay") }
}
}
internal enum Unavailable {
/// Sending messages is currently not available.
internal static var message: String { Localization.tr("Localizable", "secure_messaging.chat.unavailable.message", fallback: "Sending messages is currently not available.") }
}
}
}
internal enum Survey {
internal enum Action {
/// Please provide an answer.
Expand Down
26 changes: 26 additions & 0 deletions GliaWidgets/Public/Glia/Glia+EngagementLauncher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Foundation

extension Glia {
/// Retrieves an instance of `EngagementLauncher`.
///
/// - Parameters:
/// - queueIds: A list of queue IDs to be used for the engagement launcher. When nil, the default queues will be used.
///
/// - Returns:
/// - `EngagementLauncher` instance.
public func getEngagementLauncher(queueIds: [String]) throws -> EngagementLauncher {
let parameters = try getEngagementParameters(in: queueIds)
loggerPhase.logger.info("Returning an Engagement Launcher")
return try EngagementLauncher { [weak self] engagementKind, sceneProvider in
try self?.resolveEngagementState(
engagementKind: engagementKind,
sceneProvider: sceneProvider,
configuration: parameters.configuration,
interactor: parameters.interactor,
features: parameters.features,
viewFactory: parameters.viewFactory,
ongoingEngagementMediaStreams: parameters.ongoingEngagementMediaStreams
)
}
}
}
Loading
Loading