WIP: Call message Ui improvements

pull/560/head
Ryan Zhao 3 years ago
parent 78971b7d09
commit 0a3d84d5c8

@ -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 = "<group>"; };
76EB03C318170B33006006FC /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
7B0EFDED274F598600FFAAE7 /* TimestampUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimestampUtils.swift; sourceTree = "<group>"; };
7B0EFDEF275084AA00FFAAE7 /* CallMessageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallMessageCell.swift; sourceTree = "<group>"; };
7B1581E1271E743B00848B49 /* OWSSounds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSSounds.swift; sourceTree = "<group>"; };
7B1581E3271FC59C00848B49 /* CallModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallModal.swift; sourceTree = "<group>"; };
7B1581E5271FD2A100848B49 /* VideoPreviewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPreviewVC.swift; sourceTree = "<group>"; };
@ -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 */,

@ -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

@ -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)
}
}
}

@ -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()

@ -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

@ -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

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "CallIncoming.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "CallOutgoing.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -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 {

@ -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.")

@ -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
*/

@ -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
/**

@ -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")! }
}

@ -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
}
}
Loading…
Cancel
Save