Sketch out TypingIndicatorCell.

This commit is contained in:
Matthew Chen 2018-11-01 12:47:08 -04:00
parent eedc9f9a26
commit 63d88ef5cb
8 changed files with 162 additions and 18 deletions

View File

@ -53,6 +53,8 @@ typedef NS_OPTIONS(NSUInteger, OWSDirectionalRectCorner) {
- (CGFloat)minWidth;
- (CGFloat)minHeight;
@end
NS_ASSUME_NONNULL_END

View File

@ -273,6 +273,11 @@ const CGFloat kOWSMessageCellCornerRadius_Small = 4;
return (kOWSMessageCellCornerRadius_Large * 2);
}
- (CGFloat)minHeight
{
return (kOWSMessageCellCornerRadius_Large * 2);
}
@end
NS_ASSUME_NONNULL_END

View File

@ -10,28 +10,146 @@ public class TypingIndicatorCell: ConversationViewCell {
@objc
public static let cellReuseIdentifier = "TypingIndicatorCell"
@available(*, unavailable, message:"use other constructor instead.")
@available(*, unavailable, message:"use other constructor instead.")
@objc
public required init(coder aDecoder: NSCoder) {
notImplemented()
}
private let kAvatarSize: CGFloat = 36
private let kAvatarHSpacing: CGFloat = 8
private let avatarView = AvatarImageView()
private let bubbleView = OWSBubbleView()
private let typingIndicatorView = TypingIndicatorView()
private var viewConstraints = [NSLayoutConstraint]()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
private func commonInit() {
self.layoutMargins = .zero
self.contentView.layoutMargins = .zero
bubbleView.layoutMargins = .zero
bubbleView.addSubview(typingIndicatorView)
contentView.addSubview(bubbleView)
avatarView.autoSetDimension(.width, toSize: kAvatarSize)
avatarView.autoSetDimension(.height, toSize: kAvatarSize)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc
public override func loadForDisplay() {
guard let conversationStyle = self.conversationStyle else {
owsFailDebug("Missing conversationStyle")
return
}
bubbleView.bubbleColor = conversationStyle.bubbleColor(isIncoming: true)
typingIndicatorView.startAnimation()
typingIndicatorView.addBackgroundView(withBackgroundColor: UIColor.red)
viewConstraints.append(contentsOf: [
bubbleView.autoPinEdge(toSuperviewEdge: .leading, withInset: conversationStyle.gutterLeading),
bubbleView.autoPinEdge(toSuperviewEdge: .trailing, withInset: conversationStyle.gutterTrailing, relation: .greaterThanOrEqual),
bubbleView.autoPinTopToSuperviewMargin(withInset: 0),
bubbleView.autoPinBottomToSuperviewMargin(withInset: 0),
typingIndicatorView.autoPinEdge(toSuperviewEdge: .leading, withInset: conversationStyle.textInsetHorizontal),
typingIndicatorView.autoPinEdge(toSuperviewEdge: .trailing, withInset: conversationStyle.textInsetHorizontal),
typingIndicatorView.autoPinTopToSuperviewMargin(withInset: conversationStyle.textInsetTop),
typingIndicatorView.autoPinBottomToSuperviewMargin(withInset: conversationStyle.textInsetBottom)
])
if let avatarView = configureAvatarView() {
contentView.addSubview(avatarView)
viewConstraints.append(contentsOf: [
bubbleView.autoPinLeading(toTrailingEdgeOf: avatarView, offset: kAvatarHSpacing),
bubbleView.autoAlignAxis(.horizontal, toSameAxisOf: avatarView)
])
} else {
avatarView.removeFromSuperview()
}
}
private func configureAvatarView() -> UIView? {
guard let viewItem = self.viewItem else {
owsFailDebug("Missing viewItem")
return nil
}
guard let typingIndicators = viewItem.interaction as? TypingIndicatorInteraction else {
owsFailDebug("Missing typingIndicators")
return nil
}
guard shouldShowAvatar() else {
return nil
}
guard let colorName = viewItem.authorConversationColorName else {
owsFailDebug("Missing authorConversationColorName")
return nil
}
guard let authorAvatarImage =
OWSContactAvatarBuilder(signalId: typingIndicators.recipientId,
colorName: ConversationColorNameForString(colorName),
diameter: UInt(kAvatarSize)).build() else {
owsFailDebug("Could build avatar image")
return nil
}
avatarView.image = authorAvatarImage
return avatarView
}
private func shouldShowAvatar() -> Bool {
guard let viewItem = self.viewItem else {
owsFailDebug("Missing viewItem")
return false
}
return viewItem.isGroupThread
}
@objc
public override func cellSize() -> CGSize {
return .zero
guard let conversationStyle = self.conversationStyle else {
owsFailDebug("Missing conversationStyle")
return .zero
}
let insetsSize = CGSize(width: conversationStyle.textInsetHorizontal * 2,
height: conversationStyle.textInsetTop + conversationStyle.textInsetBottom)
let typingIndicatorSize = typingIndicatorView.sizeThatFits(.zero)
let bubbleSize = CGSizeAdd(insetsSize, typingIndicatorSize)
if shouldShowAvatar() {
let avatarSize = CGSize(width: kAvatarSize, height: kAvatarSize)
return CGSizeCeil(CGSize(width: avatarSize.width + kAvatarHSpacing + bubbleSize.width,
height: max(avatarSize.height, bubbleSize.height)))
} else {
return bubbleSize
}
}
@objc
public override func prepareForReuse() {
super.prepareForReuse()
NSLayoutConstraint.deactivate(viewConstraints)
viewConstraints = [NSLayoutConstraint]()
avatarView.image = nil
avatarView.removeFromSuperview()
typingIndicatorView.stopAnimation()
NotificationCenter.default.removeObserver(self)
}
}

View File

@ -143,14 +143,24 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
{
OWSAssertDebug(transaction);
if (self.interaction.interactionType != OWSInteractionType_IncomingMessage) {
_authorConversationColorName = nil;
return;
switch (self.interaction.interactionType) {
case OWSInteractionType_TypingIndicator: {
OWSTypingIndicatorInteraction *typingIndicator = (OWSTypingIndicatorInteraction *)self.interaction;
_authorConversationColorName =
[TSContactThread conversationColorNameForRecipientId:typingIndicator.recipientId
transaction:transaction];
break;
}
case OWSInteractionType_IncomingMessage: {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.interaction;
_authorConversationColorName =
[TSContactThread conversationColorNameForRecipientId:incomingMessage.authorId transaction:transaction];
break;
}
default:
_authorConversationColorName = nil;
break;
}
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)self.interaction;
_authorConversationColorName =
[TSContactThread conversationColorNameForRecipientId:incomingMessage.authorId transaction:transaction];
}
- (NSString *)itemId

View File

@ -16,12 +16,6 @@
private let dot2 = DotView(dotType: .dotType2)
private let dot3 = DotView(dotType: .dotType3)
override public var isHidden: Bool {
didSet {
Logger.verbose("\(oldValue) -> \(isHidden)")
}
}
@available(*, unavailable, message:"use other constructor instead.")
required init(coder aDecoder: NSCoder) {
notImplemented()
@ -46,6 +40,11 @@
self.alignment = .center
}
@objc
public override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: TypingIndicatorView.kMaxRadiusPt * 3 + kDotMaxHSpacing * 2, height: TypingIndicatorView.kMaxRadiusPt)
}
@objc
public func startAnimation() {
}
@ -86,9 +85,6 @@
self.layer.addSublayer(shapeLayer)
updateLayer()
// self.text = text
//
// setupSubviews()
}
private func updateLayer() {

View File

@ -193,6 +193,11 @@ CG_INLINE CGSize CGSizeScale(CGSize size, CGFloat factor)
return CGSizeMake(size.width * factor, size.height * factor);
}
CG_INLINE CGSize CGSizeAdd(CGSize left, CGSize right)
{
return CGSizeMake(left.width + right.width, left.height + right.height);
}
CGFloat CGHairlineWidth(void);
NS_ASSUME_NONNULL_END

View File

@ -11,6 +11,9 @@ NS_ASSUME_NONNULL_BEGIN
@class TSInvalidIdentityKeyReceivingErrorMessage;
typedef NSString *ConversationColorName NS_STRING_ENUM;
ConversationColorName ConversationColorNameForString(NSString *value);
extern ConversationColorName const ConversationColorNameCrimson;
extern ConversationColorName const ConversationColorNameVermilion;
extern ConversationColorName const ConversationColorNameBurlap;

View File

@ -19,6 +19,11 @@
NS_ASSUME_NONNULL_BEGIN
ConversationColorName ConversationColorNameForString(NSString *value)
{
return value;
}
ConversationColorName const ConversationColorNameCrimson = @"red";
ConversationColorName const ConversationColorNameVermilion = @"orange";
ConversationColorName const ConversationColorNameBurlap = @"brown";