Skip to content

Commit

Permalink
Add QuickReplyButton UI
Browse files Browse the repository at this point in the history
Added QuickReplyView which displays left-aligned button's grid
Added handling QR button actions
Added displaying QR messages

MOB-2395
  • Loading branch information
Egor Egorov authored and github-review-helper committed Jul 21, 2023
1 parent 26547eb commit 53f16d1
Show file tree
Hide file tree
Showing 15 changed files with 472 additions and 58 deletions.
48 changes: 48 additions & 0 deletions GliaWidgets.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@
84681A8E2A5ED76300DD7406 /* ChatViewModel+GVA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681A8D2A5ED76300DD7406 /* ChatViewModel+GVA.swift */; };
84681A952A61844000DD7406 /* ChatViewModelTests+Gva.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681A942A61844000DD7406 /* ChatViewModelTests+Gva.swift */; };
84681A982A61853300DD7406 /* GvaOption.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681A972A61853300DD7406 /* GvaOption.Mock.swift */; };
84681A9B2A669D8800DD7406 /* QuickReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681A9A2A669D8800DD7406 /* QuickReplyView.swift */; };
84681A9D2A669DB500DD7406 /* QuickReplyButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681A9C2A669DB500DD7406 /* QuickReplyButtonCell.swift */; };
84681A9F2A66B70400DD7406 /* LeftAlignedCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681A9E2A66B70400DD7406 /* LeftAlignedCollectionViewFlowLayout.swift */; };
84681AA12A66B9F100DD7406 /* SelfSizingCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681AA02A66B9F100DD7406 /* SelfSizingCollectionView.swift */; };
84681AA32A66D90000DD7406 /* AdjustedTouchAreaButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681AA22A66D90000DD7406 /* AdjustedTouchAreaButton.swift */; };
84681AA72A681EF900DD7406 /* QuickReplyButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681AA62A681EF900DD7406 /* QuickReplyButtonStyle.swift */; };
846A5C3429CB3A130049B29F /* ScreenShareHandler.Implementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A5C3329CB3A130049B29F /* ScreenShareHandler.Implementation.swift */; };
846A5C3629CB3E270049B29F /* ScreenShareHandler.Mock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A5C3529CB3E270049B29F /* ScreenShareHandler.Mock.swift */; };
846A5C3929D18D400049B29F /* ScreenShareHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A5C3829D18D400049B29F /* ScreenShareHandlerTests.swift */; };
Expand Down Expand Up @@ -1020,6 +1026,12 @@
84681A8D2A5ED76300DD7406 /* ChatViewModel+GVA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatViewModel+GVA.swift"; sourceTree = "<group>"; };
84681A942A61844000DD7406 /* ChatViewModelTests+Gva.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatViewModelTests+Gva.swift"; sourceTree = "<group>"; };
84681A972A61853300DD7406 /* GvaOption.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GvaOption.Mock.swift; sourceTree = "<group>"; };
84681A9A2A669D8800DD7406 /* QuickReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickReplyView.swift; sourceTree = "<group>"; };
84681A9C2A669DB500DD7406 /* QuickReplyButtonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickReplyButtonCell.swift; sourceTree = "<group>"; };
84681A9E2A66B70400DD7406 /* LeftAlignedCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftAlignedCollectionViewFlowLayout.swift; sourceTree = "<group>"; };
84681AA02A66B9F100DD7406 /* SelfSizingCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelfSizingCollectionView.swift; sourceTree = "<group>"; };
84681AA22A66D90000DD7406 /* AdjustedTouchAreaButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjustedTouchAreaButton.swift; sourceTree = "<group>"; };
84681AA62A681EF900DD7406 /* QuickReplyButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickReplyButtonStyle.swift; sourceTree = "<group>"; };
846A5C3329CB3A130049B29F /* ScreenShareHandler.Implementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenShareHandler.Implementation.swift; sourceTree = "<group>"; };
846A5C3529CB3E270049B29F /* ScreenShareHandler.Mock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenShareHandler.Mock.swift; sourceTree = "<group>"; };
846A5C3829D18D400049B29F /* ScreenShareHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenShareHandlerTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2095,6 +2107,7 @@
1AC7A7B42587A07D00567FF8 /* Action */,
1A60B0132567FC6400E53F53 /* Style */,
1A60B0142567FC7000E53F53 /* Button.swift */,
84681AA22A66D90000DD7406 /* AdjustedTouchAreaButton.swift */,
);
path = Button;
sourceTree = "<group>";
Expand Down Expand Up @@ -2187,6 +2200,8 @@
1A63B2F0257A3F0F00508478 /* Common */ = {
isa = PBXGroup;
children = (
84681AA52A681E8400DD7406 /* LeftAlignedCollectionViewFlowLayout */,
84681AA42A681E6900DD7406 /* SelfSizingCollectionView */,
1AA738B025790D4B00E1120F /* Alert */,
);
path = Common;
Expand Down Expand Up @@ -2999,6 +3014,32 @@
path = Mocks;
sourceTree = "<group>";
};
84681A992A669D5000DD7406 /* QuickReply */ = {
isa = PBXGroup;
children = (
84681A9A2A669D8800DD7406 /* QuickReplyView.swift */,
84681A9C2A669DB500DD7406 /* QuickReplyButtonCell.swift */,
84681AA62A681EF900DD7406 /* QuickReplyButtonStyle.swift */,
);
path = QuickReply;
sourceTree = "<group>";
};
84681AA42A681E6900DD7406 /* SelfSizingCollectionView */ = {
isa = PBXGroup;
children = (
84681AA02A66B9F100DD7406 /* SelfSizingCollectionView.swift */,
);
path = SelfSizingCollectionView;
sourceTree = "<group>";
};
84681AA52A681E8400DD7406 /* LeftAlignedCollectionViewFlowLayout */ = {
isa = PBXGroup;
children = (
84681A9E2A66B70400DD7406 /* LeftAlignedCollectionViewFlowLayout.swift */,
);
path = LeftAlignedCollectionViewFlowLayout;
sourceTree = "<group>";
};
846A5C3729D18D220049B29F /* ScreenShareHandler */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3199,6 +3240,7 @@
C0175A262A67D431001FACDE /* GVA */ = {
isa = PBXGroup;
children = (
84681A992A669D5000DD7406 /* QuickReply */,
C0175A162A5D30D7001FACDE /* GvaResponseTextView.swift */,
C0175A222A65614E001FACDE /* GvaPersistentButtonView.swift */,
C0175A242A66A431001FACDE /* GvaPersistentButtonOptionView.swift */,
Expand Down Expand Up @@ -4084,6 +4126,7 @@
84D5B9642A151B6100807F92 /* QuickLookBased.Mock.swift in Sources */,
311CAFCD29F8FAE20067B59F /* SecureConversations.TranscriptModel+CustomCard.swift in Sources */,
9A19926B27D3BA8700161AAE /* ViewFactory.Environment.Mock.swift in Sources */,
84681A9B2A669D8800DD7406 /* QuickReplyView.swift in Sources */,
1A6EB05725A717CB0007081A /* ChatMessage.swift in Sources */,
1AA738B225790D5A00E1120F /* AlertView.swift in Sources */,
845E2F8E283FB5B500C04D56 /* Theme.Survey.SingleQuestion.Accessibility.swift in Sources */,
Expand Down Expand Up @@ -4138,6 +4181,7 @@
C0D2F08229A4E75200803B47 /* Header.Mock.swift in Sources */,
1A4AD3B3256D2A7600468BFB /* VisitorChatMessageStyle.swift in Sources */,
845E2F98283FC9A900C04D56 /* Theme.Survey.OptionButton.swift in Sources */,
84681A9F2A66B70400DD7406 /* LeftAlignedCollectionViewFlowLayout.swift in Sources */,
84265E60298D7B2900D65842 /* ScreenSharingCoordinator+Environment.swift in Sources */,
9AB196DC27C3FFCC00FD60AB /* Call.Environment.Interface.swift in Sources */,
3197F7AF29E95527008EE9F7 /* SystemMessageView.swift in Sources */,
Expand Down Expand Up @@ -4182,6 +4226,7 @@
845A28FC28AFF092008558EA /* URLScheme.swift in Sources */,
75F58EE127E7D5300065BA2D /* Survey.ViewController.Props.swift in Sources */,
754CC61527E27C42005676E9 /* Survey.Checkbox.swift in Sources */,
84681AA72A681EF900DD7406 /* QuickReplyButtonStyle.swift in Sources */,
1A4AD3CA256E864800468BFB /* ThemeColorStyle.swift in Sources */,
AFA2FDF228907E9D00428E6D /* GliaViewController.Mock.swift in Sources */,
9AB196DE27C3FFF400FD60AB /* Call.Environment.Mock.swift in Sources */,
Expand Down Expand Up @@ -4215,6 +4260,7 @@
9A19926527D3BA3A00161AAE /* UIKitBased.Mock.swift in Sources */,
C0D2F06B29A4DAA000803B47 /* VideoCallViewMock.swift in Sources */,
1AFB1E6225F7AE1300CA460D /* ChatEngagementFile.swift in Sources */,
84681A9D2A669DB500DD7406 /* QuickReplyButtonCell.swift in Sources */,
3100EEF2293E214B00D57F71 /* SecureConversations.Coordinator.swift in Sources */,
1AA738AE2578E0D500E1120F /* ConnectAnimationView.swift in Sources */,
754CC61627E2816F005676E9 /* Survey.InputQuestionView.swift in Sources */,
Expand Down Expand Up @@ -4276,6 +4322,7 @@
755D186B29A6A5830009F5E8 /* WelcomeStyle+MessageTitleStyle.swift in Sources */,
75940981298D38C2008B173A /* VisitorCodeView+NumberView.swift in Sources */,
7529F2B427E1D503004D3581 /* Survey.swift in Sources */,
84681AA12A66B9F100DD7406 /* SelfSizingCollectionView.swift in Sources */,
1A5F494B25CA86CA003E3678 /* Call.swift in Sources */,
84265E65298D7B2900D65842 /* ScreenSharingView.swift in Sources */,
9A1992ED27D6C19E00161AAE /* FileSystemStorage.Environment.Mock.swift in Sources */,
Expand Down Expand Up @@ -4366,6 +4413,7 @@
7594093D298D376B008B173A /* RemoteConfiguration+AssetsBuilder.swift in Sources */,
9A3E1D9B27B73246005634EB /* FoundationBased.Mock.swift in Sources */,
75FF151427F3A2D600FE7BE2 /* Theme+Survey.swift in Sources */,
84681AA32A66D90000DD7406 /* AdjustedTouchAreaButton.swift in Sources */,
1A60AFE825669C5000E53F53 /* ChatStyle.swift in Sources */,
75940984298D38C2008B173A /* VisitorCodeViewController.swift in Sources */,
1A4AF5C725AEEA42002CD0F4 /* Operator+Extensions.swift in Sources */,
Expand Down
24 changes: 24 additions & 0 deletions GliaWidgets/Sources/Component/Button/AdjustedTouchAreaButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import UIKit

class AdjustedTouchAreaButton: UIButton {
private var touchAreaInsets: TouchAreaInsets?

init(touchAreaInsets: TouchAreaInsets? = nil) {
super.init(frame: .zero)
self.touchAreaInsets = touchAreaInsets
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
guard let insets = touchAreaInsets else {
return super.point(inside: point, with: event)
}

let area = bounds.insetBy(dx: insets.dx, dy: insets.dy)

return area.contains(point)
}
}
16 changes: 4 additions & 12 deletions GliaWidgets/Sources/Component/Button/Button.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import UIKit

class Button: UIButton {
class Button: AdjustedTouchAreaButton {
var tap: (() -> Void)?

var touchAreaInsets: TouchAreaInsets?

override var isEnabled: Bool {
didSet {
super.isEnabled = isEnabled
Expand All @@ -16,7 +18,7 @@ class Button: UIButton {
init(kind: ButtonKind, tap: (() -> Void)? = nil) {
self.kind = kind
self.tap = tap
super.init(frame: .zero)
super.init(touchAreaInsets: kind.properties.touchAreaInsets)
setup()
layout()
}
Expand Down Expand Up @@ -58,14 +60,4 @@ class Button: UIButton {
@objc private func tapped() {
tap?()
}

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
guard let insets = kind.properties.touchAreaInsets else {
return super.point(inside: point, with: event)
}

let area = bounds.insetBy(dx: insets.dx, dy: insets.dy)

return area.contains(point)
}
}
14 changes: 13 additions & 1 deletion GliaWidgets/Sources/Theme/Theme+Gva.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ extension Theme {
)
)

return .init(persistentButton: persistentButton)
let quickReplyButtonStyle: GvaQuickReplyButtonStyle = .init(
textFont: font.buttonLabel,
textColor: Color.primary,
backgroundColor: .fill(color: Color.baseLight),
cornerRadius: 10,
borderColor: Color.primary,
borderWidth: 1
)

return .init(
persistentButton: persistentButton,
quickReplyButtonStyle: quickReplyButtonStyle
)
}
}
45 changes: 29 additions & 16 deletions GliaWidgets/Sources/View/Chat/ChatView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ChatView: EngagementView {
var selectCustomCardOption: ((HtmlMetadata.Option, MessageRenderer.Message.Identifier) -> Void)?
var gvaButtonTapped: ((GvaOption) -> Void)?

private lazy var quickReplyView = QuickReplyView(style: style.gliaVirtualAssistant.quickReplyButtonStyle)
private let style: ChatStyle
private var messageEntryViewBottomConstraint: NSLayoutConstraint!
private var callBubble: BubbleView?
Expand Down Expand Up @@ -161,6 +162,10 @@ class ChatView: EngagementView {
typingIndicatorView.heightAnchor.constraint(equalToConstant: 10)
])

addSubview(quickReplyView)
constraints += quickReplyView.layoutIn(safeAreaLayoutGuide, edges: .horizontal)
constraints += quickReplyView.topAnchor.constraint(equalTo: tableAndIndicatorStack.bottomAnchor)

addSubview(messageEntryView)
let messageEntryInsets = UIEdgeInsets(
top: 0,
Expand All @@ -176,7 +181,7 @@ class ChatView: EngagementView {
constraints += messageEntryViewBottomConstraint

constraints += messageEntryView.layoutIn(safeAreaLayoutGuide, edges: .horizontal)
constraints += messageEntryView.topAnchor.constraint(equalTo: tableAndIndicatorStack.bottomAnchor)
constraints += messageEntryView.topAnchor.constraint(equalTo: quickReplyView.bottomAnchor)

addSubview(unreadMessageIndicatorView)
unreadMessageIndicatorView.translatesAutoresizingMaskIntoConstraints = false
Expand Down Expand Up @@ -310,7 +315,11 @@ extension ChatView {
tableView.reloadData()
}

func renderHeaderProps() {
func renderQuickReply(props: QuickReplyView.Props) {
quickReplyView.props = props
}

private func renderHeaderProps() {
header.props = props.header
}
}
Expand Down Expand Up @@ -371,24 +380,28 @@ extension ChatView {
case .systemMessage(let message):
return systemMessageContent(message)
case let .gvaPersistentButton(message, button, showImage, imageUrl):
return gvaPersistenButtonContent(
return gvaPersistentButtonContent(
message,
button: button,
showImage: showImage,
imageUrl: imageUrl
)
case let .gvaResponseText(message, text, showImage, imageUrl):
return gvaResponseTextContent(
let view = gvaResponseTextView(
message,
text: text,
text: text.content,
showImage: showImage,
imageUrl: imageUrl
)
case let .gvaQuickReply(_, button):
// Temporary, since UI hasn't been implemented
let textView = UITextView()
textView.text = "Quick Reply: \(button.content)"
return .gvaQuickReply(textView)
return .gvaResponseText(view)
case let .gvaQuickReply(message, button, showImage, imageUrl):
let view = gvaResponseTextView(
message,
text: button.content,
showImage: showImage,
imageUrl: imageUrl
)
return .gvaQuickReply(view)
case let .gvaGallery(_, gallery):
// Temporary, since UI hasn't been implemented
let textView = UITextView()
Expand Down Expand Up @@ -838,12 +851,12 @@ extension ChatView {
return .unreadMessagesDivider(messageDivider)
}

private func gvaResponseTextContent(
private func gvaResponseTextView(
_ message: ChatMessage,
text: GvaResponseText,
text: NSAttributedString,
showImage: Bool,
imageUrl: String?
) -> ChatItemCell.Content {
) -> GvaResponseTextView {
let view = GvaResponseTextView(
with: style.operatorMessage,
environment: .init(
Expand All @@ -856,7 +869,7 @@ extension ChatView {
)
view.appendContent(
.attributedText(
text.content,
text,
accessibility: Self.operatorAccessibilityMessage(
for: message,
operator: style.accessibility.operator,
Expand All @@ -875,10 +888,10 @@ extension ChatView {
view.linkTapped = { [weak self] in self?.linkTapped?($0) }
view.showsOperatorImage = showImage
view.setOperatorImage(fromUrl: imageUrl, animated: false)
return .gvaResponseText(view)
return view
}

private func gvaPersistenButtonContent(
private func gvaPersistentButtonContent(
_ message: ChatMessage,
button: GvaButton,
showImage: Bool,
Expand Down
10 changes: 9 additions & 1 deletion GliaWidgets/Sources/View/Chat/GVA/GvaStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ public struct GliaVirtualAssistantStyle {
/// Style of Persistent Button
public var persistentButton: GvaPersistentButtonStyle

/// Style for Quick Reply buttons.
public var quickReplyButtonStyle: GvaQuickReplyButtonStyle

/// - Parameters:
/// - persistentButton: Style of Persistent Button
/// - quickReplyButtonStyle: Style for Quick Reply buttons.
public init(
persistentButton: GvaPersistentButtonStyle
persistentButton: GvaPersistentButtonStyle,
quickReplyButtonStyle: GvaQuickReplyButtonStyle
) {
self.persistentButton = persistentButton
self.quickReplyButtonStyle = quickReplyButtonStyle
}

mutating func apply(
Expand Down
Loading

0 comments on commit 53f16d1

Please sign in to comment.