From 0a3d84d5c8ea56bc8bedb5f012f28674d98c4c24 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Fri, 26 Nov 2021 16:57:57 +1100 Subject: [PATCH] WIP: Call message Ui improvements --- Session.xcodeproj/project.pbxproj | 4 + .../Call Management/SessionCallManager.swift | 2 +- .../Message Cells/CallMessageCell.swift | 70 ++++++++++++++++++ .../Message Cells/MessageCell.swift | 6 +- .../Views & Modals/MessagesTableView.swift | 1 + Session/Meta/AppDelegate.swift | 8 +- .../CallIncoming.imageset/CallIncoming.pdf | Bin 0 -> 5103 bytes .../CallIncoming.imageset/Contents.json | 12 +++ .../CallOutgoing.imageset/CallOutgoing.pdf | Bin 0 -> 5106 bytes .../CallOutgoing.imageset/Contents.json | 12 +++ Session/Shared/ConversationCell.swift | 2 +- .../MessageReceiver+Handling.swift | 4 +- SessionMessagingKit/Threads/TSThread.h | 7 ++ SessionMessagingKit/Threads/TSThread.m | 12 +++ SessionUIKit/Style Guide/Colors.swift | 1 + .../Contents.json | 38 ++++++++++ 16 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 Session/Conversations/Message Cells/CallMessageCell.swift create mode 100644 Session/Meta/Images.xcassets/Session/CallIncoming.imageset/CallIncoming.pdf create mode 100644 Session/Meta/Images.xcassets/Session/CallIncoming.imageset/Contents.json create mode 100644 Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/CallOutgoing.pdf create mode 100644 Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/Contents.json create mode 100644 SessionUIKit/Style Guide/Colors.xcassets/session_call_message_background.colorset/Contents.json diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index cd2c46514..97c79506e 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -137,6 +137,7 @@ 76C87F19181EFCE600C4ACAB /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 76C87F18181EFCE600C4ACAB /* MediaPlayer.framework */; }; 76EB054018170B33006006FC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB03C318170B33006006FC /* AppDelegate.m */; }; 7B0EFDEE274F598600FFAAE7 /* TimestampUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B0EFDED274F598600FFAAE7 /* TimestampUtils.swift */; }; + 7B0EFDF0275084AA00FFAAE7 /* CallMessageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B0EFDEF275084AA00FFAAE7 /* CallMessageCell.swift */; }; 7B1581E2271E743B00848B49 /* OWSSounds.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E1271E743B00848B49 /* OWSSounds.swift */; }; 7B1581E4271FC59D00848B49 /* CallModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E3271FC59C00848B49 /* CallModal.swift */; }; 7B1581E6271FD2A100848B49 /* VideoPreviewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B1581E5271FD2A100848B49 /* VideoPreviewVC.swift */; }; @@ -1127,6 +1128,7 @@ 76EB03C218170B33006006FC /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 76EB03C318170B33006006FC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 7B0EFDED274F598600FFAAE7 /* TimestampUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimestampUtils.swift; sourceTree = ""; }; + 7B0EFDEF275084AA00FFAAE7 /* CallMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMessageCell.swift; sourceTree = ""; }; 7B1581E1271E743B00848B49 /* OWSSounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSSounds.swift; sourceTree = ""; }; 7B1581E3271FC59C00848B49 /* CallModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallModal.swift; sourceTree = ""; }; 7B1581E5271FD2A100848B49 /* VideoPreviewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPreviewVC.swift; sourceTree = ""; }; @@ -2245,6 +2247,7 @@ B835247825C38D880089A44F /* MessageCell.swift */, B835249A25C3AB650089A44F /* VisibleMessageCell.swift */, B83524A425C3BA4B0089A44F /* InfoMessageCell.swift */, + 7B0EFDEF275084AA00FFAAE7 /* CallMessageCell.swift */, B8041AA625C90927003C2166 /* TypingIndicatorCell.swift */, B8041A7325C8F758003C2166 /* Content Views */, ); @@ -5003,6 +5006,7 @@ B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */, 76EB054018170B33006006FC /* AppDelegate.m in Sources */, 340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */, + 7B0EFDF0275084AA00FFAAE7 /* CallMessageCell.swift in Sources */, C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */, C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */, B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, diff --git a/Session/Calls/Call Management/SessionCallManager.swift b/Session/Calls/Call Management/SessionCallManager.swift index 990833cfb..ed3ccc1be 100644 --- a/Session/Calls/Call Management/SessionCallManager.swift +++ b/Session/Calls/Call Management/SessionCallManager.swift @@ -133,7 +133,7 @@ public final class SessionCallManager: NSObject { callUpdate.supportsDTMF = false } - public func handleIncomingCallOfferInBusyOrUnenabledState(offerMessage: CallMessage, using transaction: YapDatabaseReadWriteTransaction) { + public func handleIncomingCallOfferInBusyState(offerMessage: CallMessage, using transaction: YapDatabaseReadWriteTransaction) { guard let caller = offerMessage.sender, let thread = TSContactThread.fetch(for: caller, using: transaction) else { return } let message = CallMessage() message.uuid = offerMessage.uuid diff --git a/Session/Conversations/Message Cells/CallMessageCell.swift b/Session/Conversations/Message Cells/CallMessageCell.swift new file mode 100644 index 000000000..1715210a7 --- /dev/null +++ b/Session/Conversations/Message Cells/CallMessageCell.swift @@ -0,0 +1,70 @@ +import UIKit + +final class CallMessageCell : MessageCell { + private lazy var iconImageViewWidthConstraint = iconImageView.set(.width, to: CallMessageCell.iconSize) + private lazy var iconImageViewHeightConstraint = iconImageView.set(.height, to: CallMessageCell.iconSize) + + // MARK: UI Components + private lazy var iconImageView = UIImageView() + + private lazy var label: UILabel = { + let result = UILabel() + result.numberOfLines = 0 + result.lineBreakMode = .byWordWrapping + result.font = .boldSystemFont(ofSize: Values.smallFontSize) + result.textColor = Colors.text + result.textAlignment = .center + return result + }() + + private lazy var container: UIView = { + let result = UIView() + result.set(.height, to: 50) + result.layer.cornerRadius = 18 + result.backgroundColor = Colors.callMessageBackground + result.addSubview(label) + label.autoCenterInSuperview() + result.addSubview(iconImageView) + iconImageView.autoVCenterInSuperview() + iconImageView.pin(.left, to: .left, of: result, withInset: CallMessageCell.inset) + return result + }() + + // MARK: Settings + private static let iconSize: CGFloat = 16 + private static let inset = Values.mediumSpacing + private static let margin = UIScreen.main.bounds.width * 0.1 + + override class var identifier: String { "CallMessageCell" } + + // MARK: Lifecycle + override func setUpViewHierarchy() { + super.setUpViewHierarchy() + iconImageViewWidthConstraint.isActive = true + iconImageViewHeightConstraint.isActive = true + addSubview(container) + container.pin(.left, to: .left, of: self, withInset: CallMessageCell.margin) + container.pin(.top, to: .top, of: self, withInset: CallMessageCell.inset) + container.pin(.right, to: .right, of: self, withInset: -CallMessageCell.margin) + container.pin(.bottom, to: .bottom, of: self, withInset: -CallMessageCell.inset) + } + + // MARK: Updating + override func update() { + guard let message = viewItem?.interaction as? TSMessage, message.isCallMessage else { return } + let icon: UIImage? + switch message.interactionType() { + case .outgoingMessage: icon = UIImage(named: "CallOutgoing") + case .incomingMessage: icon = UIImage(named: "CallIncoming") + default: icon = nil + } + if let icon = icon { + iconImageView.image = icon.withTint(Colors.text) + } + iconImageViewWidthConstraint.constant = (icon != nil) ? CallMessageCell.iconSize : 0 + iconImageViewHeightConstraint.constant = (icon != nil) ? CallMessageCell.iconSize : 0 + Storage.read { transaction in + self.label.text = message.previewText(with: transaction) + } + } +} diff --git a/Session/Conversations/Message Cells/MessageCell.swift b/Session/Conversations/Message Cells/MessageCell.swift index a2d846692..56d93b2b2 100644 --- a/Session/Conversations/Message Cells/MessageCell.swift +++ b/Session/Conversations/Message Cells/MessageCell.swift @@ -46,7 +46,11 @@ class MessageCell : UITableViewCell { static func getCellType(for viewItem: ConversationViewItem) -> MessageCell.Type { switch viewItem.interaction { case is TSIncomingMessage: fallthrough - case is TSOutgoingMessage: return VisibleMessageCell.self + case is TSOutgoingMessage: + if let message = viewItem.interaction as? TSMessage, message.isCallMessage { + return CallMessageCell.self + } + return VisibleMessageCell.self case is TSInfoMessage: return InfoMessageCell.self case is TypingIndicatorInteraction: return TypingIndicatorCell.self default: preconditionFailure() diff --git a/Session/Conversations/Views & Modals/MessagesTableView.swift b/Session/Conversations/Views & Modals/MessagesTableView.swift index d5648f2bb..0f19cff94 100644 --- a/Session/Conversations/Views & Modals/MessagesTableView.swift +++ b/Session/Conversations/Views & Modals/MessagesTableView.swift @@ -31,6 +31,7 @@ final class MessagesTableView : UITableView { register(VisibleMessageCell.self, forCellReuseIdentifier: VisibleMessageCell.identifier) register(InfoMessageCell.self, forCellReuseIdentifier: InfoMessageCell.identifier) register(TypingIndicatorCell.self, forCellReuseIdentifier: TypingIndicatorCell.identifier) + register(CallMessageCell.self, forCellReuseIdentifier: CallMessageCell.identifier) separatorStyle = .none backgroundColor = .clear showsVerticalScrollIndicator = false diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 0d2bbdeb9..7ca15247e 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -51,11 +51,15 @@ extension AppDelegate { // Pre offer messages MessageReceiver.handleNewCallOfferMessageIfNeeded = { (message, transaction) in guard CurrentAppContext().isMainApp else { return } + guard SSKPreferences.areCallsEnabled else { + // TODO: Show tips and insert a missing call message + return + } let callManager = AppEnvironment.shared.callManager // Ignore pre offer message after the same call instance has been generated if let currentCall = callManager.currentCall, currentCall.uuid == message.uuid! { return } - guard callManager.currentCall == nil && SSKPreferences.areCallsEnabled else { - callManager.handleIncomingCallOfferInBusyOrUnenabledState(offerMessage: message, using: transaction) + guard callManager.currentCall == nil else { + callManager.handleIncomingCallOfferInBusyState(offerMessage: message, using: transaction) return } // Create incoming call message diff --git a/Session/Meta/Images.xcassets/Session/CallIncoming.imageset/CallIncoming.pdf b/Session/Meta/Images.xcassets/Session/CallIncoming.imageset/CallIncoming.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fbc5a4a875971060d79f642f11a200ff3d3d7e9d GIT binary patch literal 5103 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 N$x`s~sq1P`{0~2=8sY!| literal 0 HcmV?d00001 diff --git a/Session/Meta/Images.xcassets/Session/CallIncoming.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/CallIncoming.imageset/Contents.json new file mode 100644 index 000000000..083076594 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/CallIncoming.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "CallIncoming.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/CallOutgoing.pdf b/Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/CallOutgoing.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f6550ced9dff0058648e4f21d80f9ad7818beac8 GIT binary patch literal 5106 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 QJvb5x19NjLXefgJ2O=Q_G5`Po literal 0 HcmV?d00001 diff --git a/Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/Contents.json b/Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/Contents.json new file mode 100644 index 000000000..d6bb5d534 --- /dev/null +++ b/Session/Meta/Images.xcassets/Session/CallOutgoing.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "CallOutgoing.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 2eaf22d3a..d0e98b494 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -228,7 +228,7 @@ final class ConversationCell : UITableViewCell { } statusIndicatorView.backgroundColor = nil let lastMessage = threadViewModel.lastMessageForInbox - if let lastMessage = lastMessage as? TSOutgoingMessage { + if let lastMessage = lastMessage as? TSOutgoingMessage, !lastMessage.isCallMessage { let image: UIImage let status = MessageRecipientStatusUtils.recipientStatus(outgoingMessage: lastMessage) switch status { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 8c4ecba30..184111889 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -269,10 +269,12 @@ extension MessageReceiver { public static func handleCallMessage(_ message: CallMessage, using transaction: Any) { guard let timestamp = message.sentTimestamp, TimestampUtils.isWithinOneMinute(timestamp: timestamp) else { return } + let transaction = transaction as! YapDatabaseReadWriteTransaction + // Ignore call messages from threads without outgoing messages + guard let sender = message.sender, let thread = TSContactThread.fetch(for: sender, using: transaction), thread.hasOutgoingInteraction(with: transaction) else { return } switch message.kind! { case .preOffer: print("[Calls] Received pre-offer message.") - let transaction = transaction as! YapDatabaseReadWriteTransaction handleNewCallOfferMessageIfNeeded?(message, transaction) case .offer: print("[Calls] Received offer message.") diff --git a/SessionMessagingKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h index c2449397a..71818c3d0 100644 --- a/SessionMessagingKit/Threads/TSThread.h +++ b/SessionMessagingKit/Threads/TSThread.h @@ -38,6 +38,13 @@ BOOL IsNoteToSelfEnabled(void); */ - (NSString *)name; +/** + * Returns if there is any outgoing interations in this thread. + * + * @return YES if there are outgoing interations, NO otherwise. + */ +- (BOOL)hasOutgoingInteractionWithTransaction:(YapDatabaseReadTransaction *)transaction; + /** * @returns recipientId for each recipient in the thread */ diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index 6283a324d..bf4bad523 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -153,6 +153,18 @@ BOOL IsNoteToSelfEnabled(void) return @[]; } +- (BOOL)hasOutgoingInteractionWithTransaction:(YapDatabaseReadTransaction *)transaction +{ + __block BOOL hasOutgoingInteraction = NO; + [self enumerateInteractionsWithTransaction:transaction usingBlock:^(TSInteraction *interaction, BOOL *stop) { + if ([interaction interactionType] == OWSInteractionType_OutgoingMessage) { + hasOutgoingInteraction = YES; + *stop = YES; + } + }]; + return hasOutgoingInteraction; +} + #pragma mark Interactions /** diff --git a/SessionUIKit/Style Guide/Colors.swift b/SessionUIKit/Style Guide/Colors.swift index 06f4e3095..e6e092829 100644 --- a/SessionUIKit/Style Guide/Colors.swift +++ b/SessionUIKit/Style Guide/Colors.swift @@ -41,4 +41,5 @@ public final class Colors : NSObject { @objc public static var pnOptionBackground: UIColor { UIColor(named: "session_pn_option_background")! } @objc public static var pnOptionBorder: UIColor { UIColor(named: "session_pn_option_border")! } @objc public static var pathsBuilding: UIColor { UIColor(named: "session_paths_building")! } + @objc public static var callMessageBackground: UIColor { UIColor(named: "session_call_message_background")! } } diff --git a/SessionUIKit/Style Guide/Colors.xcassets/session_call_message_background.colorset/Contents.json b/SessionUIKit/Style Guide/Colors.xcassets/session_call_message_background.colorset/Contents.json new file mode 100644 index 000000000..843f0f6c1 --- /dev/null +++ b/SessionUIKit/Style Guide/Colors.xcassets/session_call_message_background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF5", + "green" : "0xF5", + "red" : "0xF5" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x21", + "green" : "0x21", + "red" : "0x21" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +}