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 77 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
31b9ce2
Update dependencies declared in `Podfile` and `Package.swift`
Nov 11, 2024
9cf8f00
Add EntryWidget UI
rasmustautsglia Sep 23, 2024
23b75b8
Add Engagement Launcher interface and getter from Glia
ykyivskyi-gl Sep 25, 2024
aa162bf
Add EntryWidget embedded view
rasmustautsglia Sep 26, 2024
3f315f0
Implement EngagementLauncher logic
ykyivskyi-gl Sep 30, 2024
fed031d
Add Unified Customization to EntryWidget
rasmustautsglia Oct 3, 2024
fba32c1
Update Entry Widget media types texts
rasmustautsglia Oct 8, 2024
84aedff
Implement QueuesMonitor to observe queues' engagement type updates
ykyivskyi-gl Oct 8, 2024
b251c86
Add remote configuration for secure conversations
igorkravchenko Oct 11, 2024
74a1fee
Integrate queues monitor and engagement launcher into EntryWidget
ykyivskyi-gl Oct 13, 2024
b4be030
Add new localization keys and update existing for local strings for SC
igorkravchenko Oct 14, 2024
12a9bbb
Make entry widget height dynamic
rasmustautsglia Oct 16, 2024
66fae32
Update 'Check Messages' button and margins on SC Welcome screen
igorkravchenko Oct 15, 2024
9da4a6a
Add new public interfaces to the Entry Widget
rasmustautsglia Oct 18, 2024
c9ce2df
Cover QueuesMonitor with unit tests
ykyivskyi-gl Oct 18, 2024
c174501
Add new localizations for the Entry Widget.
AndriiHorishniiMOC Oct 16, 2024
9b5cbd2
Add Entry Widget Loading view design
rasmustautsglia Oct 21, 2024
e483995
Introduce SC bottom banner UI on chat screen
igorkravchenko Oct 21, 2024
1375d47
Implement unified customization for SC bottom banner
igorkravchenko Oct 23, 2024
794bdbd
Make passed getEngagementLauncher queuesId paramater non-nullable
ykyivskyi-gl Oct 24, 2024
e987649
Leave Current Conversation dialog UI
Oct 25, 2024
1caa44b
Remote config for Leave Current Conversation dialog
Oct 25, 2024
64c8bed
Hide the "Secure Messaging" if visitor is not authenticated
rasmustautsglia Oct 24, 2024
786badd
Snapshot tests for Leave Current Conversation dialog
Oct 25, 2024
316a987
Add accessibility modifiers to the Entry Widget
AndriiHorishniiMOC Oct 22, 2024
e110fd8
Add new send message unavailability banner
igorkravchenko Oct 24, 2024
c36b428
Add unified customization for new SC unavailability indicator for chat
igorkravchenko Oct 26, 2024
66c46df
Make EntryWidget sheet landscape adaptable
rasmustautsglia Oct 28, 2024
1cfff60
Replace unavailability dialog with banner view on Transcript screen
igorkravchenko Oct 28, 2024
cca73b9
Toggle SC bottom banner visibility based on view model
igorkravchenko Oct 29, 2024
14c2c35
Use queues from QueuesMonitor to determine Secure Conversations avail…
ykyivskyi-gl Oct 30, 2024
6344812
Improve the Entry Widget Style structures
AndriiHorishniiMOC Oct 28, 2024
50c118f
Hide EntryWidget sheet before engagement
rasmustautsglia Nov 4, 2024
d5332b7
Add snapshot tests to EntryWidget
rasmustautsglia Nov 1, 2024
04ddcb8
Remove rebasing issue
rasmustautsglia Nov 5, 2024
d21aff3
Optimize using of strings for the Entry Widget
AndriiHorishniiMOC Nov 4, 2024
57ab709
Introduce disabled state for ChatMessageEntry style
igorkravchenko Nov 2, 2024
e3ecc9f
Bump up deployment target from iOS 13 to 14
AndriiHorishniiMOC Nov 6, 2024
e355fe5
Introduce disabled state for file upload list
igorkravchenko Nov 7, 2024
627284f
Update dependencies declared in `Podfile` and `Package.swift`
Nov 12, 2024
dc1b17c
Disable send message and pick media buttons instead of hiding them
igorkravchenko Nov 11, 2024
30f761e
Chat to Secure Conversation transfer
Nov 8, 2024
8f0cce5
Add SC unread message badge on Entry Widget
ykyivskyi-gl Nov 11, 2024
45b6d58
Add logs and telemetry for Entry Widget
rasmustautsglia Nov 12, 2024
68e5eb6
Update default global colors according to color palette
igorkravchenko Oct 22, 2024
e8ece5f
Remove deprecated and existing startEngagement methods
ykyivskyi-gl Nov 14, 2024
3279a1c
Fix remote configuration not being applied to Entry Widget
rasmustautsglia Nov 15, 2024
bb0c414
Change Chat Button label in EntryWidget
rasmustautsglia Nov 13, 2024
19d8ec8
SecureConversation business logic
Nov 18, 2024
c619ea3
Add disabled unified customization for disabled state for chat messag…
AndriiHorishniiMOC Nov 15, 2024
5a91a4c
Add snapshot tests for bottom banner
igorkravchenko Nov 19, 2024
23e15c3
Add entry point for EntryWidget for Secure Conversation
ykyivskyi-gl Nov 20, 2024
b3ee803
ViewController refactoring
Nov 20, 2024
b4eabd5
Add pending secure messaging logic to EntryWidget
Nov 19, 2024
72481cf
Apply Unified UI for the SC
AndriiHorishniiMOC Nov 20, 2024
562fd7f
Change subheadline color In EntryWidget
rasmustautsglia Nov 20, 2024
dcd5ef7
Extend SCv2 logic with unreadMessageCount
Nov 25, 2024
b722127
Add accessibility identifiers to Entry Widget items
AndriiHorishniiMOC Nov 25, 2024
2074820
Bump up Core SDK version to 2.0.2 and update SC interface
igorkravchenko Nov 27, 2024
7783878
Show Entry Widget on SC top banner click
ykyivskyi-gl Nov 26, 2024
96c0eae
Add Unit and Snapshot tests for top banner on Secure Conversations
ykyivskyi-gl Nov 28, 2024
4b07c3f
Fix memory leak in Chat module
Nov 28, 2024
4601e51
Apply unified UI for SC's top banner on ChatView
ykyivskyi-gl Nov 29, 2024
c081584
Isolate pending interaction logic in separate model
igorkravchenko Nov 29, 2024
91b0ddb
Fix strict version in Podfile.lock
Dec 6, 2024
178f47d
Improve mark as read SC messages
ykyivskyi-gl Dec 5, 2024
5addc2a
Address unavailability banner showing up for SC flow
igorkravchenko Dec 5, 2024
271356c
Update SC availability taking into account 'transferring' state
igorkravchenko Dec 5, 2024
a2ce534
Create PendingInteraction model after configuration
igorkravchenko Dec 11, 2024
47273bb
Update dependencies declared in `Podfile` and `Package.swift`
Dec 13, 2024
de6b977
Handle ongoing engagement in EntryWidget
rasmustautsglia Dec 6, 2024
914730c
Create interface for resuming call visualizer
rasmustautsglia Dec 17, 2024
a7559b4
Add a state property to determine resume behavior
rasmustautsglia Dec 19, 2024
93b9644
Fill area under message entry with same bg color as message entry
igorkravchenko Dec 19, 2024
0e2e5ef
Handle `follow_up` end reason
Dec 23, 2024
2245426
Fix keeping wrong interactor state after CV engagement
Dec 23, 2024
fdaf96c
Fix handling engagement ended flow
Dec 24, 2024
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
470 changes: 438 additions & 32 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