ConversationViewItem -> protocol
This commit is contained in:
parent
f56ac96d31
commit
06eae47e09
|
@ -67,66 +67,67 @@ struct MessageActionBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
extension ConversationViewItem {
|
||||
@objc
|
||||
class ConversationViewItemActions: NSObject {
|
||||
|
||||
@objc
|
||||
func textActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
class func textActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
var actions: [MenuAction] = []
|
||||
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(replyAction)
|
||||
|
||||
if self.hasBodyTextActionContent {
|
||||
let copyTextAction = MessageActionBuilder.copyText(conversationViewItem: self, delegate: delegate)
|
||||
if conversationViewItem.hasBodyTextActionContent {
|
||||
let copyTextAction = MessageActionBuilder.copyText(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(copyTextAction)
|
||||
}
|
||||
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(deleteAction)
|
||||
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(showDetailsAction)
|
||||
|
||||
return actions
|
||||
}
|
||||
|
||||
@objc
|
||||
func mediaActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
class func mediaActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
var actions: [MenuAction] = []
|
||||
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(replyAction)
|
||||
|
||||
if self.hasMediaActionContent {
|
||||
let copyMediaAction = MessageActionBuilder.copyMedia(conversationViewItem: self, delegate: delegate)
|
||||
if conversationViewItem.hasMediaActionContent {
|
||||
let copyMediaAction = MessageActionBuilder.copyMedia(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(copyMediaAction)
|
||||
if self.canSaveMedia() {
|
||||
let saveMediaAction = MessageActionBuilder.saveMedia(conversationViewItem: self, delegate: delegate)
|
||||
if conversationViewItem.canSaveMedia() {
|
||||
let saveMediaAction = MessageActionBuilder.saveMedia(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(saveMediaAction)
|
||||
}
|
||||
}
|
||||
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(deleteAction)
|
||||
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
actions.append(showDetailsAction)
|
||||
|
||||
return actions
|
||||
}
|
||||
|
||||
@objc
|
||||
func quotedMessageActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: self, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: self, delegate: delegate)
|
||||
class func quotedMessageActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let replyAction = MessageActionBuilder.reply(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
let showDetailsAction = MessageActionBuilder.showDetails(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
|
||||
return [replyAction, deleteAction, showDetailsAction]
|
||||
}
|
||||
|
||||
@objc
|
||||
func infoMessageActions(delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: self, delegate: delegate)
|
||||
class func infoMessageActions(conversationViewItem: ConversationViewItem, delegate: MessageActionsDelegate) -> [MenuAction] {
|
||||
let deleteAction = MessageActionBuilder.deleteMessage(conversationViewItem: conversationViewItem, delegate: delegate)
|
||||
|
||||
return [deleteAction]
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewCell;
|
||||
@class ConversationViewItem;
|
||||
@class OWSContactOffersInteraction;
|
||||
@class OWSContactsManager;
|
||||
@class TSAttachmentPointer;
|
||||
|
@ -19,13 +18,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@class TSOutgoingMessage;
|
||||
@class TSQuotedMessage;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@protocol ConversationViewCellDelegate <NSObject>
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(id<ConversationViewItem>)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(id<ConversationViewItem>)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(id<ConversationViewItem>)viewItem;
|
||||
- (void)conversationCell:(ConversationViewCell *)cell
|
||||
didLongpressSystemMessageViewItem:(ConversationViewItem *)viewItem;
|
||||
didLongpressSystemMessageViewItem:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
#pragma mark - System Cell
|
||||
|
||||
|
@ -68,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic, nullable, weak) id<ConversationViewCellDelegate> delegate;
|
||||
|
||||
@property (nonatomic, nullable) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, nullable) id<ConversationViewItem> viewItem;
|
||||
|
||||
// Cells are prefetched but expensive cells (e.g. media) should only load
|
||||
// when visible and unload when no longer visible. Non-visible cells can
|
||||
|
|
|
@ -7,14 +7,15 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
@class TSAttachmentStream;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@interface OWSAudioMessageView : UIStackView
|
||||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream
|
||||
isIncoming:(BOOL)isIncoming
|
||||
viewItem:(ConversationViewItem *)viewItem
|
||||
viewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
- (void)createContents;
|
||||
|
|
|
@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic) BOOL isIncoming;
|
||||
@property (nonatomic, weak) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, weak) id<ConversationViewItem> viewItem;
|
||||
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
||||
|
||||
@property (nonatomic, nullable) UIButton *audioPlayPauseButton;
|
||||
|
@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachmentStream
|
||||
isIncoming:(BOOL)isIncoming
|
||||
viewItem:(ConversationViewItem *)viewItem
|
||||
viewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
{
|
||||
self = [super init];
|
||||
|
|
|
@ -6,7 +6,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@class ContactShareViewModel;
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@class OWSContact;
|
||||
@class OWSQuotedReplyModel;
|
||||
@class TSAttachmentPointer;
|
||||
|
@ -25,27 +27,27 @@ extern const UIDataDetectorTypes kOWSAllowedDataDetectorTypes;
|
|||
|
||||
@protocol OWSMessageBubbleViewDelegate
|
||||
|
||||
- (void)didTapImageViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapImageViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIView *)imageView;
|
||||
|
||||
- (void)didTapVideoViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapVideoViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIView *)imageView;
|
||||
|
||||
- (void)didTapAudioViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
- (void)didTapAudioViewItem:(id<ConversationViewItem>)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream;
|
||||
|
||||
- (void)didTapTruncatedTextMessage:(ConversationViewItem *)conversationItem;
|
||||
- (void)didTapTruncatedTextMessage:(id<ConversationViewItem>)conversationItem;
|
||||
|
||||
- (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
||||
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply;
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply;
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem
|
||||
quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
failedThumbnailDownloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer;
|
||||
|
||||
- (void)didTapContactShareViewItem:(ConversationViewItem *)viewItem;
|
||||
- (void)didTapContactShareViewItem:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
- (void)didTapSendMessageToContactShare:(ContactShareViewModel *)contactShare
|
||||
NS_SWIFT_NAME(didTapSendMessage(toContactShare:));
|
||||
|
@ -60,7 +62,7 @@ extern const UIDataDetectorTypes kOWSAllowedDataDetectorTypes;
|
|||
|
||||
@interface OWSMessageBubbleView : UIView
|
||||
|
||||
@property (nonatomic, nullable) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, nullable) id<ConversationViewItem> viewItem;
|
||||
|
||||
@property (nonatomic) ConversationStyle *conversationStyle;
|
||||
|
||||
|
|
|
@ -2,19 +2,20 @@
|
|||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationStyle;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@interface OWSMessageFooterView : UIStackView
|
||||
|
||||
- (void)configureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
isOverlayingMedia:(BOOL)isOverlayingMedia
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
isIncoming:(BOOL)isIncoming;
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem;
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem;
|
||||
|
||||
- (void)prepareForReuse;
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
#pragma mark - Load
|
||||
|
||||
- (void)configureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
isOverlayingMedia:(BOOL)isOverlayingMedia
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
isIncoming:(BOOL)isIncoming
|
||||
|
@ -186,7 +186,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[self.statusIndicatorImageView.layer addAnimation:animation forKey:@"animation"];
|
||||
}
|
||||
|
||||
- (BOOL)isFailedOutgoingMessage:(ConversationViewItem *)viewItem
|
||||
- (BOOL)isFailedOutgoingMessage:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -200,7 +200,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return messageStatus == MessageReceiptStatusFailed;
|
||||
}
|
||||
|
||||
- (void)configureLabelsWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureLabelsWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -217,7 +217,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
self.timestampLabel.text = timestampLabelText.localizedUppercaseString;
|
||||
}
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -243,7 +243,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return CGSizeCeil(result);
|
||||
}
|
||||
|
||||
- (nullable NSString *)messageStatusTextForConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (nullable NSString *)messageStatusTextForConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
if (viewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage) {
|
||||
|
|
|
@ -5,16 +5,17 @@
|
|||
extern const CGFloat OWSMessageHeaderViewDateHeaderVMargin;
|
||||
|
||||
@class ConversationStyle;
|
||||
@class ConversationViewItem;
|
||||
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSMessageHeaderView : UIStackView
|
||||
|
||||
- (void)loadForDisplayWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)loadForDisplayWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
@end
|
||||
|
|
|
@ -72,7 +72,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
[self addSubview:self.stackView];
|
||||
}
|
||||
|
||||
- (void)loadForDisplayWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)loadForDisplayWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -100,7 +100,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
];
|
||||
}
|
||||
|
||||
- (CGFloat)strokeThicknessWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGFloat)strokeThicknessWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -111,7 +111,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
}
|
||||
}
|
||||
|
||||
- (UIColor *)strokeColorWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (UIColor *)strokeColorWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -122,7 +122,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)configureLabelsWithViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)configureLabelsWithViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
||||
|
@ -158,7 +158,7 @@ const CGFloat OWSMessageHeaderViewDateHeaderVMargin = 23;
|
|||
}
|
||||
}
|
||||
|
||||
- (CGSize)measureWithConversationViewItem:(ConversationViewItem *)viewItem
|
||||
- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
|
||||
conversationStyle:(ConversationStyle *)conversationStyle
|
||||
{
|
||||
OWSAssertDebug(viewItem);
|
||||
|
|
|
@ -175,8 +175,8 @@ typedef enum : NSUInteger {
|
|||
@property (nonatomic, readonly) ConversationViewLayout *layout;
|
||||
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
||||
|
||||
@property (nonatomic) NSArray<ConversationViewItem *> *viewItems;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache;
|
||||
@property (nonatomic) NSArray<id<ConversationViewItem>> *viewItems;
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, id<ConversationViewItem>> *viewItemCache;
|
||||
|
||||
@property (nonatomic, nullable) AVAudioRecorder *audioRecorder;
|
||||
@property (nonatomic, nullable) OWSAudioPlayer *audioAttachmentPlayer;
|
||||
|
@ -717,7 +717,7 @@ typedef enum : NSUInteger {
|
|||
- (NSIndexPath *_Nullable)indexPathOfUnreadMessagesIndicator
|
||||
{
|
||||
NSInteger row = 0;
|
||||
for (ConversationViewItem *viewItem in self.viewItems) {
|
||||
for (id<ConversationViewItem> viewItem in self.viewItems) {
|
||||
if (viewItem.unreadIndicator) {
|
||||
return [NSIndexPath indexPathForRow:row inSection:0];
|
||||
}
|
||||
|
@ -1553,7 +1553,7 @@ typedef enum : NSUInteger {
|
|||
OWSLogInfo(@"didChangePreferredContentSize");
|
||||
|
||||
// Evacuate cached cell sizes.
|
||||
for (ConversationViewItem *viewItem in self.viewItems) {
|
||||
for (id<ConversationViewItem> viewItem in self.viewItems) {
|
||||
[viewItem clearCachedLayoutState];
|
||||
}
|
||||
[self resetContentAndLayout];
|
||||
|
@ -1933,12 +1933,12 @@ typedef enum : NSUInteger {
|
|||
|
||||
#pragma mark - MessageActionsDelegate
|
||||
|
||||
- (void)messageActionsShowDetailsForItem:(ConversationViewItem *)conversationViewItem
|
||||
- (void)messageActionsShowDetailsForItem:(id<ConversationViewItem>)conversationViewItem
|
||||
{
|
||||
[self showDetailViewForViewItem:conversationViewItem];
|
||||
}
|
||||
|
||||
- (void)messageActionsReplyToItem:(ConversationViewItem *)conversationViewItem
|
||||
- (void)messageActionsReplyToItem:(id<ConversationViewItem>)conversationViewItem
|
||||
{
|
||||
[self populateReplyForViewItem:conversationViewItem];
|
||||
}
|
||||
|
@ -2006,27 +2006,32 @@ typedef enum : NSUInteger {
|
|||
|
||||
#pragma mark - ConversationViewCellDelegate
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressMediaViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem mediaActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions mediaActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressTextViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem textActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions textActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressQuoteViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem quotedMessageActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions quotedMessageActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
- (void)conversationCell:(ConversationViewCell *)cell didLongpressSystemMessageViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)conversationCell:(ConversationViewCell *)cell
|
||||
didLongpressSystemMessageViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
NSArray<MenuAction *> *messageActions = [viewItem infoMessageActionsWithDelegate:self];
|
||||
NSArray<MenuAction *> *messageActions =
|
||||
[ConversationViewItemActions infoMessageActionsWithConversationViewItem:viewItem delegate:self];
|
||||
[self presentMessageActions:messageActions withFocusedCell:cell];
|
||||
}
|
||||
|
||||
|
@ -2141,7 +2146,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
#pragma mark - OWSMessageBubbleViewDelegate
|
||||
|
||||
- (void)didTapImageViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapImageViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIView *)imageView
|
||||
{
|
||||
|
@ -2172,7 +2177,7 @@ typedef enum : NSUInteger {
|
|||
[vc presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView];
|
||||
}
|
||||
|
||||
- (void)didTapVideoViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapVideoViewItem:(id<ConversationViewItem>)viewItem
|
||||
attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
imageView:(UIImageView *)imageView
|
||||
{
|
||||
|
@ -2201,7 +2206,7 @@ typedef enum : NSUInteger {
|
|||
[vc presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView];
|
||||
}
|
||||
|
||||
- (void)didTapAudioViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
- (void)didTapAudioViewItem:(id<ConversationViewItem>)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -2231,7 +2236,7 @@ typedef enum : NSUInteger {
|
|||
[self.audioAttachmentPlayer playWithPlaybackAudioCategory];
|
||||
}
|
||||
|
||||
- (void)didTapTruncatedTextMessage:(ConversationViewItem *)conversationItem
|
||||
- (void)didTapTruncatedTextMessage:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -2241,7 +2246,7 @@ typedef enum : NSUInteger {
|
|||
[self.navigationController pushViewController:view animated:YES];
|
||||
}
|
||||
|
||||
- (void)didTapContactShareViewItem:(ConversationViewItem *)conversationItem
|
||||
- (void)didTapContactShareViewItem:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -2276,7 +2281,7 @@ typedef enum : NSUInteger {
|
|||
[self.contactShareViewHelper showAddToContactsWithContactShare:contactShare fromViewController:self];
|
||||
}
|
||||
|
||||
- (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
|
||||
- (void)didTapFailedIncomingAttachment:(id<ConversationViewItem>)viewItem
|
||||
attachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
@ -2296,7 +2301,7 @@ typedef enum : NSUInteger {
|
|||
[self handleUnsentMessageTap:message];
|
||||
}
|
||||
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem
|
||||
quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
failedThumbnailDownloadAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
|
||||
{
|
||||
|
@ -2334,7 +2339,7 @@ typedef enum : NSUInteger {
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)didTapConversationItem:(ConversationViewItem *)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
- (void)didTapConversationItem:(id<ConversationViewItem>)viewItem quotedReply:(OWSQuotedReplyModel *)quotedReply
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -2469,7 +2474,7 @@ typedef enum : NSUInteger {
|
|||
return @(groupIndex);
|
||||
}
|
||||
|
||||
- (void)showDetailViewForViewItem:(ConversationViewItem *)conversationItem
|
||||
- (void)showDetailViewForViewItem:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
@ -2484,7 +2489,7 @@ typedef enum : NSUInteger {
|
|||
[self.navigationController pushViewController:view animated:YES];
|
||||
}
|
||||
|
||||
- (void)populateReplyForViewItem:(ConversationViewItem *)conversationItem
|
||||
- (void)populateReplyForViewItem:(id<ConversationViewItem>)conversationItem
|
||||
{
|
||||
OWSLogDebug(@"user did tap reply");
|
||||
|
||||
|
@ -2559,7 +2564,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
NSIndexPath *_Nullable indexPathOfUnreadIndicator = [self indexPathOfUnreadMessagesIndicator];
|
||||
if (indexPathOfUnreadIndicator) {
|
||||
ConversationViewItem *oldIndicatorItem = [self viewItemForIndex:indexPathOfUnreadIndicator.row];
|
||||
id<ConversationViewItem> oldIndicatorItem = [self viewItemForIndex:indexPathOfUnreadIndicator.row];
|
||||
OWSAssertDebug(oldIndicatorItem);
|
||||
|
||||
// TODO ideally this would be happening within the *same* transaction that caused the unreadMessageIndicator
|
||||
|
@ -2673,7 +2678,7 @@ typedef enum : NSUInteger {
|
|||
BOOL isScrolledUp = scrollSpaceToBottom > pageHeight * 1.f;
|
||||
|
||||
if (self.viewItems.count > 0) {
|
||||
ConversationViewItem *lastViewItem = [self.viewItems lastObject];
|
||||
id<ConversationViewItem> lastViewItem = [self.viewItems lastObject];
|
||||
OWSAssertDebug(lastViewItem);
|
||||
|
||||
if (lastViewItem.interaction.timestampForSorting > self.lastVisibleTimestamp) {
|
||||
|
@ -3289,7 +3294,7 @@ typedef enum : NSUInteger {
|
|||
case YapDatabaseViewChangeUpdate: {
|
||||
YapCollectionKey *collectionKey = rowChange.collectionKey;
|
||||
if (collectionKey.key) {
|
||||
ConversationViewItem *_Nullable viewItem = self.viewItemCache[collectionKey.key];
|
||||
id<ConversationViewItem> _Nullable viewItem = self.viewItemCache[collectionKey.key];
|
||||
if (viewItem) {
|
||||
[self reloadInteractionForViewItem:viewItem];
|
||||
} else {
|
||||
|
@ -3373,7 +3378,8 @@ typedef enum : NSUInteger {
|
|||
(unsigned long)rowChange.finalIndex);
|
||||
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
|
||||
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
id<ConversationViewItem> _Nullable viewItem =
|
||||
[self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
if ([viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]) {
|
||||
TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
|
||||
if (!outgoingMessage.isFromLinkedDevice) {
|
||||
|
@ -3508,7 +3514,7 @@ typedef enum : NSUInteger {
|
|||
isOnlyModifyingLastMessage = NO;
|
||||
break;
|
||||
case YapDatabaseViewChangeInsert: {
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
id<ConversationViewItem> _Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
if (([viewItem.interaction isKindOfClass:[TSIncomingMessage class]] ||
|
||||
[viewItem.interaction isKindOfClass:[TSOutgoingMessage class]])
|
||||
&& rowChange.finalIndex >= oldViewItemCount) {
|
||||
|
@ -3524,7 +3530,7 @@ typedef enum : NSUInteger {
|
|||
if (rowChange.changes == YapDatabaseViewChangedDependency) {
|
||||
continue;
|
||||
}
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
id<ConversationViewItem> _Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
|
||||
if (([viewItem.interaction isKindOfClass:[TSIncomingMessage class]] ||
|
||||
[viewItem.interaction isKindOfClass:[TSOutgoingMessage class]])
|
||||
&& rowChange.finalIndex >= oldViewItemCount) {
|
||||
|
@ -3855,7 +3861,7 @@ typedef enum : NSUInteger {
|
|||
return lastVisibleIndexPath;
|
||||
}
|
||||
|
||||
- (nullable ConversationViewItem *)lastVisibleViewItem
|
||||
- (nullable id<ConversationViewItem>)lastVisibleViewItem
|
||||
{
|
||||
NSIndexPath *_Nullable lastVisibleIndexPath = [self lastVisibleIndexPath];
|
||||
if (!lastVisibleIndexPath) {
|
||||
|
@ -3870,7 +3876,7 @@ typedef enum : NSUInteger {
|
|||
- (void)didScrollToBottom
|
||||
{
|
||||
|
||||
ConversationViewItem *_Nullable lastVisibleViewItem = [self.viewItems lastObject];
|
||||
id<ConversationViewItem> _Nullable lastVisibleViewItem = [self.viewItems lastObject];
|
||||
if (lastVisibleViewItem) {
|
||||
uint64_t lastVisibleTimestamp = lastVisibleViewItem.interaction.timestampForSorting;
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, lastVisibleTimestamp);
|
||||
|
@ -3883,7 +3889,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
- (void)updateLastVisibleTimestamp
|
||||
{
|
||||
ConversationViewItem *_Nullable lastVisibleViewItem = [self lastVisibleViewItem];
|
||||
id<ConversationViewItem> _Nullable lastVisibleViewItem = [self lastVisibleViewItem];
|
||||
if (lastVisibleViewItem) {
|
||||
uint64_t lastVisibleTimestamp = lastVisibleViewItem.interaction.timestampForSorting;
|
||||
self.lastVisibleTimestamp = MAX(self.lastVisibleTimestamp, lastVisibleTimestamp);
|
||||
|
@ -4640,7 +4646,7 @@ typedef enum : NSUInteger {
|
|||
// any new items inserted while we were not observing. We therefore find the
|
||||
// first item at or after the "view horizon". See the comments below which explain
|
||||
// the "view horizon".
|
||||
ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject;
|
||||
id<ConversationViewItem> _Nullable lastViewItem = self.viewItems.lastObject;
|
||||
BOOL hasAddedNewItems = (lastViewItem && previousLastTimestamp
|
||||
&& lastViewItem.interaction.timestamp > previousLastTimestamp.unsignedLongLongValue);
|
||||
|
||||
|
@ -4671,7 +4677,7 @@ typedef enum : NSUInteger {
|
|||
// We'll use this later to update the view to reflect any changes made while
|
||||
// we were not observing the database. See extendRangeToIncludeUnobservedItems
|
||||
// and the logic above.
|
||||
ConversationViewItem *_Nullable lastViewItem = self.viewItems.lastObject;
|
||||
id<ConversationViewItem> _Nullable lastViewItem = self.viewItems.lastObject;
|
||||
if (lastViewItem) {
|
||||
self.previousLastTimestamp = @(lastViewItem.interaction.timestamp);
|
||||
} else {
|
||||
|
@ -4717,7 +4723,7 @@ typedef enum : NSUInteger {
|
|||
NSUInteger mid = (left + right) / 2;
|
||||
OWSAssertDebug(left <= mid);
|
||||
OWSAssertDebug(mid < right);
|
||||
ConversationViewItem *viewItem = self.viewItems[mid];
|
||||
id<ConversationViewItem> viewItem = self.viewItems[mid];
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
right = mid;
|
||||
} else {
|
||||
|
@ -4726,7 +4732,7 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
}
|
||||
OWSAssertDebug(left == right);
|
||||
ConversationViewItem *viewItem = self.viewItems[left];
|
||||
id<ConversationViewItem> viewItem = self.viewItems[left];
|
||||
if (viewItem.interaction.timestamp >= viewHorizonTimestamp) {
|
||||
OWSLogInfo(@"firstIndexPathAtViewHorizonTimestamp: %zd / %zd", left, self.viewItems.count);
|
||||
return [NSIndexPath indexPathForRow:(NSInteger) left inSection:0];
|
||||
|
@ -4860,8 +4866,8 @@ typedef enum : NSUInteger {
|
|||
// Returns NO on error.
|
||||
- (BOOL)reloadViewItems
|
||||
{
|
||||
NSMutableArray<ConversationViewItem *> *viewItems = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemCache = [NSMutableDictionary new];
|
||||
NSMutableArray<id<ConversationViewItem>> *viewItems = [NSMutableArray new];
|
||||
NSMutableDictionary<NSString *, id<ConversationViewItem>> *viewItemCache = [NSMutableDictionary new];
|
||||
|
||||
NSUInteger count = [self.messageMappings numberOfItemsInSection:0];
|
||||
BOOL isGroupThread = self.isGroupConversation;
|
||||
|
@ -4890,12 +4896,12 @@ typedef enum : NSUInteger {
|
|||
continue;
|
||||
}
|
||||
|
||||
ConversationViewItem *_Nullable viewItem = self.viewItemCache[interaction.uniqueId];
|
||||
id<ConversationViewItem> _Nullable viewItem = self.viewItemCache[interaction.uniqueId];
|
||||
if (!viewItem) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:interaction
|
||||
isGroupThread:isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:interaction
|
||||
isGroupThread:isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
}
|
||||
[viewItems addObject:viewItem];
|
||||
OWSAssertDebug(!viewItemCache[interaction.uniqueId]);
|
||||
|
@ -4916,7 +4922,7 @@ typedef enum : NSUInteger {
|
|||
uint64_t collapseCutoffTimestamp = [NSDate ows_millisecondsSince1970ForDate:self.collapseCutoffDate];
|
||||
|
||||
BOOL hasPlacedUnreadIndicator = NO;
|
||||
for (ConversationViewItem *viewItem in viewItems) {
|
||||
for (id<ConversationViewItem> viewItem in viewItems) {
|
||||
BOOL canShowDate = NO;
|
||||
switch (viewItem.interaction.interactionType) {
|
||||
case OWSInteractionType_Unknown:
|
||||
|
@ -4992,9 +4998,9 @@ typedef enum : NSUInteger {
|
|||
//
|
||||
// NOTE: This logic uses the break properties which are set in the previous pass.
|
||||
for (NSUInteger i = 0; i < viewItems.count; i++) {
|
||||
ConversationViewItem *viewItem = viewItems[i];
|
||||
ConversationViewItem *_Nullable previousViewItem = (i > 0 ? viewItems[i - 1] : nil);
|
||||
ConversationViewItem *_Nullable nextViewItem = (i + 1 < viewItems.count ? viewItems[i + 1] : nil);
|
||||
id<ConversationViewItem> viewItem = viewItems[i];
|
||||
id<ConversationViewItem> _Nullable previousViewItem = (i > 0 ? viewItems[i - 1] : nil);
|
||||
id<ConversationViewItem> _Nullable nextViewItem = (i + 1 < viewItems.count ? viewItems[i + 1] : nil);
|
||||
BOOL shouldShowSenderAvatar = NO;
|
||||
BOOL shouldHideFooter = NO;
|
||||
BOOL isFirstInCluster = YES;
|
||||
|
@ -5143,7 +5149,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
// Whenever an interaction is modified, we need to reload it from the DB
|
||||
// and update the corresponding view item.
|
||||
- (void)reloadInteractionForViewItem:(ConversationViewItem *)viewItem
|
||||
- (void)reloadInteractionForViewItem:(id<ConversationViewItem>)viewItem
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(viewItem);
|
||||
|
@ -5164,7 +5170,7 @@ typedef enum : NSUInteger {
|
|||
}];
|
||||
}
|
||||
|
||||
- (nullable ConversationViewItem *)viewItemForIndex:(NSInteger)index
|
||||
- (nullable id<ConversationViewItem>)viewItemForIndex:(NSInteger)index
|
||||
{
|
||||
if (index < 0 || index >= (NSInteger)self.viewItems.count) {
|
||||
OWSFailDebug(@"Invalid view item index: %lu", (unsigned long)index);
|
||||
|
@ -5183,7 +5189,7 @@ typedef enum : NSUInteger {
|
|||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:indexPath.row];
|
||||
id<ConversationViewItem> _Nullable viewItem = [self viewItemForIndex:indexPath.row];
|
||||
ConversationViewCell *cell = [viewItem dequeueCellForCollectionView:self.collectionView indexPath:indexPath];
|
||||
if (!cell) {
|
||||
OWSFailDebug(@"Could not dequeue cell.");
|
||||
|
|
|
@ -43,7 +43,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
//
|
||||
// Critically, this class implements ConversationViewLayoutItem
|
||||
// and does caching of the cell's size.
|
||||
@interface ConversationViewItem : NSObject <ConversationViewLayoutItem, OWSAudioPlayerDelegate>
|
||||
@protocol ConversationViewItem <NSObject, ConversationViewLayoutItem, OWSAudioPlayerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) TSInteraction *interaction;
|
||||
|
||||
|
@ -69,14 +69,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
|
||||
@property (nonatomic, nullable) OWSUnreadIndicator *unreadIndicator;
|
||||
|
||||
@property (nonatomic, readonly) ConversationStyle *conversationStyle;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithInteraction:(TSInteraction *)interaction
|
||||
isGroupThread:(BOOL)isGroupThread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
- (ConversationViewCell *)dequeueCellForCollectionView:(UICollectionView *)collectionView
|
||||
indexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
|
@ -89,21 +81,20 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
@property (nonatomic, weak) OWSAudioMessageView *lastAudioMessageView;
|
||||
|
||||
@property (nonatomic, readonly) CGFloat audioDurationSeconds;
|
||||
|
||||
- (CGFloat)audioProgressSeconds;
|
||||
@property (nonatomic, readonly) CGFloat audioProgressSeconds;
|
||||
|
||||
#pragma mark - View State Caching
|
||||
|
||||
// These methods only apply to text & attachment messages.
|
||||
- (OWSMessageCellType)messageCellType;
|
||||
- (nullable DisplayableText *)displayableBodyText;
|
||||
- (nullable TSAttachmentStream *)attachmentStream;
|
||||
- (nullable TSAttachmentPointer *)attachmentPointer;
|
||||
- (CGSize)mediaSize;
|
||||
@property (nonatomic, readonly) OWSMessageCellType messageCellType;
|
||||
@property (nonatomic, readonly, nullable) DisplayableText *displayableBodyText;
|
||||
@property (nonatomic, readonly, nullable) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic, readonly, nullable) TSAttachmentPointer *attachmentPointer;
|
||||
@property (nonatomic, readonly) CGSize mediaSize;
|
||||
|
||||
- (nullable DisplayableText *)displayableQuotedText;
|
||||
- (nullable NSString *)quotedAttachmentMimetype;
|
||||
- (nullable NSString *)quotedRecipientId;
|
||||
@property (nonatomic, readonly, nullable) DisplayableText *displayableQuotedText;
|
||||
@property (nonatomic, readonly, nullable) NSString *quotedAttachmentMimetype;
|
||||
@property (nonatomic, readonly, nullable) NSString *quotedRecipientId;
|
||||
|
||||
// We don't want to try to load the media for this item (if any)
|
||||
// if a load has previously failed.
|
||||
|
@ -132,4 +123,15 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
|
|||
|
||||
@end
|
||||
|
||||
@interface ConversationInteractionViewItem
|
||||
: NSObject <ConversationViewItem, ConversationViewLayoutItem, OWSAudioPlayerDelegate>
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithInteraction:(TSInteraction *)interaction
|
||||
isGroupThread:(BOOL)isGroupThread
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
conversationStyle:(ConversationStyle *)conversationStyle;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -46,7 +46,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
|
||||
#pragma mark -
|
||||
|
||||
@interface ConversationViewItem ()
|
||||
@interface ConversationInteractionViewItem ()
|
||||
|
||||
@property (nonatomic, nullable) NSValue *cachedCellSize;
|
||||
|
||||
|
@ -70,12 +70,25 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
@property (nonatomic, nullable) NSString *systemMessageText;
|
||||
@property (nonatomic, nullable) TSThread *incomingMessageAuthorThread;
|
||||
@property (nonatomic, nullable) NSString *authorConversationColorName;
|
||||
@property (nonatomic, nullable) ConversationStyle *conversationStyle;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ConversationViewItem
|
||||
@implementation ConversationInteractionViewItem
|
||||
|
||||
@synthesize shouldShowDate = _shouldShowDate;
|
||||
@synthesize shouldShowSenderAvatar = _shouldShowSenderAvatar;
|
||||
@synthesize unreadIndicator = _unreadIndicator;
|
||||
@synthesize didCellMediaFailToLoad = _didCellMediaFailToLoad;
|
||||
@synthesize interaction = _interaction;
|
||||
@synthesize isFirstInCluster = _isFirstInCluster;
|
||||
@synthesize isGroupThread = _isGroupThread;
|
||||
@synthesize isLastInCluster = _isLastInCluster;
|
||||
@synthesize lastAudioMessageView = _lastAudioMessageView;
|
||||
@synthesize senderName = _senderName;
|
||||
@synthesize shouldHideFooter = _shouldHideFooter;
|
||||
|
||||
- (instancetype)initWithInteraction:(TSInteraction *)interaction
|
||||
isGroupThread:(BOOL)isGroupThread
|
||||
|
@ -293,7 +306,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
|
|||
return measurementCell;
|
||||
}
|
||||
|
||||
- (CGFloat)vSpacingWithPreviousLayoutItem:(ConversationViewItem *)previousLayoutItem
|
||||
- (CGFloat)vSpacingWithPreviousLayoutItem:(id<ConversationViewItem>)previousLayoutItem
|
||||
{
|
||||
OWSAssertDebug(previousLayoutItem);
|
||||
|
||||
|
|
|
@ -1967,10 +1967,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSAssertDebug(messageToQuote);
|
||||
OWSLogVerbose(@"%@", label);
|
||||
[DDLog flushLog];
|
||||
ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
id<ConversationViewItem> viewItem =
|
||||
[[ConversationInteractionViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
quotedMessage = [
|
||||
[OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:viewItem transaction:transaction]
|
||||
buildQuotedMessageForSending];
|
||||
|
@ -1986,10 +1987,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
transaction:transaction];
|
||||
OWSAssertDebug(messageToQuote);
|
||||
|
||||
ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
id<ConversationViewItem> viewItem =
|
||||
[[ConversationInteractionViewItem alloc] initWithInteraction:messageToQuote
|
||||
isGroupThread:thread.isGroupThread
|
||||
transaction:transaction
|
||||
conversationStyle:conversationStyle];
|
||||
quotedMessage = [
|
||||
[OWSQuotedReplyModel quotedReplyForSendingWithConversationViewItem:viewItem transaction:transaction]
|
||||
buildQuotedMessageForSending];
|
||||
|
|
|
@ -37,7 +37,7 @@ public class LongTextViewController: OWSViewController {
|
|||
guard viewItem.hasBodyText else {
|
||||
return ""
|
||||
}
|
||||
guard let displayableText = viewItem.displayableBodyText() else {
|
||||
guard let displayableText = viewItem.displayableBodyText else {
|
||||
return ""
|
||||
}
|
||||
let messageBody = displayableText.fullText
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationViewItem;
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@class GalleryItemBox;
|
||||
@class MediaDetailViewController;
|
||||
|
||||
|
@ -18,7 +19,7 @@ typedef NS_OPTIONS(NSInteger, MediaGalleryOption) {
|
|||
@protocol MediaDetailViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)mediaDetailViewController:(MediaDetailViewController *)mediaDetailViewController
|
||||
requestDeleteConversationViewItem:(ConversationViewItem *)conversationViewItem;
|
||||
requestDeleteConversationViewItem:(id<ConversationViewItem>)conversationViewItem;
|
||||
|
||||
- (void)mediaDetailViewController:(MediaDetailViewController *)mediaDetailViewController
|
||||
isPlayingVideo:(BOOL)isPlayingVideo;
|
||||
|
@ -34,7 +35,7 @@ typedef NS_OPTIONS(NSInteger, MediaGalleryOption) {
|
|||
|
||||
// If viewItem is non-null, long press will show a menu controller.
|
||||
- (instancetype)initWithGalleryItemBox:(GalleryItemBox *)galleryItemBox
|
||||
viewItem:(ConversationViewItem *_Nullable)viewItem;
|
||||
viewItem:(nullable id<ConversationViewItem>)viewItem;
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)didPressShare:(id)sender;
|
||||
|
|
|
@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic) UIButton *shareButton;
|
||||
|
||||
@property (nonatomic) TSAttachmentStream *attachmentStream;
|
||||
@property (nonatomic, nullable) ConversationViewItem *viewItem;
|
||||
@property (nonatomic, nullable) id<ConversationViewItem> viewItem;
|
||||
@property (nonatomic, nullable) UIImage *image;
|
||||
|
||||
@property (nonatomic, nullable) OWSVideoPlayer *videoPlayer;
|
||||
|
@ -63,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
- (instancetype)initWithGalleryItemBox:(GalleryItemBox *)galleryItemBox
|
||||
viewItem:(ConversationViewItem *_Nullable)viewItem
|
||||
viewItem:(nullable id<ConversationViewItem>)viewItem
|
||||
{
|
||||
self = [super initWithNibName:nil bundle:nil];
|
||||
if (!self) {
|
||||
|
|
|
@ -479,10 +479,10 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
let message = galleryItem.message
|
||||
let thread = message.thread(with: transaction)
|
||||
let conversationStyle = ConversationStyle(thread: thread)
|
||||
fetchedItem = ConversationViewItem(interaction: message,
|
||||
isGroupThread: thread.isGroupThread(),
|
||||
transaction: transaction,
|
||||
conversationStyle: conversationStyle)
|
||||
fetchedItem = ConversationInteractionViewItem(interaction: message,
|
||||
isGroupThread: thread.isGroupThread(),
|
||||
transaction: transaction,
|
||||
conversationStyle: conversationStyle)
|
||||
}
|
||||
|
||||
guard let viewItem = fetchedItem else {
|
||||
|
|
|
@ -326,7 +326,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
guard viewItem.hasBodyText else {
|
||||
return nil
|
||||
}
|
||||
guard let displayableText = viewItem.displayableBodyText() else {
|
||||
guard let displayableText = viewItem.displayableBodyText else {
|
||||
return nil
|
||||
}
|
||||
let messageBody = displayableText.fullText
|
||||
|
@ -663,7 +663,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
|||
|
||||
if let audioAttachmentPlayer = self.audioAttachmentPlayer {
|
||||
// Is this player associated with this media adapter?
|
||||
if audioAttachmentPlayer.owner as? ConversationViewItem == viewItem {
|
||||
if audioAttachmentPlayer.owner === viewItem {
|
||||
// Tap to pause & unpause.
|
||||
audioAttachmentPlayer.togglePlayState()
|
||||
return
|
||||
|
|
|
@ -39,22 +39,22 @@
|
|||
return @"abc";
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)textViewItem
|
||||
- (ConversationInteractionViewItem *)textViewItem
|
||||
{
|
||||
TSOutgoingMessage *message =
|
||||
[TSOutgoingMessage outgoingMessageInThread:self.thread messageBody:self.fakeTextMessageText attachmentId:nil];
|
||||
[message save];
|
||||
__block ConversationViewItem *viewItem = nil;
|
||||
__block ConversationInteractionViewItem *viewItem = nil;
|
||||
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
}];
|
||||
return viewItem;
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename
|
||||
- (ConversationInteractionViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename
|
||||
{
|
||||
OWSAssertDebug(filename.length > 0);
|
||||
|
||||
|
@ -74,33 +74,33 @@
|
|||
[TSOutgoingMessage outgoingMessageInThread:self.thread messageBody:nil attachmentId:attachment.uniqueId];
|
||||
[message save];
|
||||
|
||||
__block ConversationViewItem *viewItem = nil;
|
||||
__block ConversationInteractionViewItem *viewItem = nil;
|
||||
[self readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
viewItem = [[ConversationViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
viewItem = [[ConversationInteractionViewItem alloc] initWithInteraction:message
|
||||
isGroupThread:NO
|
||||
transaction:transaction
|
||||
conversationStyle:self.conversationStyle];
|
||||
}];
|
||||
|
||||
return viewItem;
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)stillImageViewItem
|
||||
- (ConversationInteractionViewItem *)stillImageViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:OWSMimeTypeImageJpeg filename:@"test-jpg.jpg"];
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)animatedImageViewItem
|
||||
- (ConversationInteractionViewItem *)animatedImageViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:OWSMimeTypeImageGif filename:@"test-gif.gif"];
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)videoViewItem
|
||||
- (ConversationInteractionViewItem *)videoViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:@"video/mp4" filename:@"test-mp4.mp4"];
|
||||
}
|
||||
|
||||
- (ConversationViewItem *)audioViewItem
|
||||
- (ConversationInteractionViewItem *)audioViewItem
|
||||
{
|
||||
return [self viewItemWithAttachmentMimetype:@"audio/mp3" filename:@"test-mp3.mp3"];
|
||||
}
|
||||
|
@ -109,7 +109,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithNonMediaMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.textViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.textViewItem;
|
||||
|
||||
XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
|
||||
[viewItem deleteAction];
|
||||
|
@ -118,7 +118,7 @@
|
|||
|
||||
- (void)testPerformDeleteActionWithPhotoMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.stillImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.stillImageViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -140,7 +140,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithAnimatedMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.animatedImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.animatedImageViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -162,7 +162,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithVideoMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.videoViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.videoViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -184,7 +184,7 @@
|
|||
|
||||
- (void)testPerformDeleteEditingActionWithAudioMessage
|
||||
{
|
||||
ConversationViewItem *viewItem = self.audioViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.audioViewItem;
|
||||
|
||||
XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
|
||||
NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
|
||||
|
@ -212,7 +212,7 @@
|
|||
UIPasteboard.generalPasteboard.items = @[];
|
||||
XCTAssertNil(UIPasteboard.generalPasteboard.string);
|
||||
|
||||
ConversationViewItem *viewItem = self.textViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.textViewItem;
|
||||
[viewItem copyTextAction];
|
||||
XCTAssertEqualObjects(self.fakeTextMessageText, UIPasteboard.generalPasteboard.string);
|
||||
}
|
||||
|
@ -224,7 +224,7 @@
|
|||
XCTAssertNil(UIPasteboard.generalPasteboard.image);
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]);
|
||||
|
||||
ConversationViewItem *viewItem = self.stillImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.stillImageViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
@ -237,7 +237,7 @@
|
|||
XCTAssertNil(UIPasteboard.generalPasteboard.image);
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]);
|
||||
|
||||
ConversationViewItem *viewItem = self.animatedImageViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.animatedImageViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
@ -249,7 +249,7 @@
|
|||
UIPasteboard.generalPasteboard.items = @[];
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]);
|
||||
|
||||
ConversationViewItem *viewItem = self.videoViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.videoViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
@ -261,7 +261,7 @@
|
|||
UIPasteboard.generalPasteboard.items = @[];
|
||||
XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]);
|
||||
|
||||
ConversationViewItem *viewItem = self.audioViewItem;
|
||||
ConversationInteractionViewItem *viewItem = self.audioViewItem;
|
||||
[viewItem copyMediaAction];
|
||||
NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3];
|
||||
XCTAssertTrue(copiedData.length > 0);
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ConversationViewItem;
|
||||
@protocol ConversationViewItem;
|
||||
|
||||
@class TSAttachmentPointer;
|
||||
@class TSAttachmentStream;
|
||||
@class TSMessage;
|
||||
|
@ -42,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
// Builds a not-yet-sent QuotedReplyModel
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(ConversationViewItem *)conversationItem
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(id<ConversationViewItem>)conversationItem
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
- (TSQuotedMessage *)buildQuotedMessageForSending;
|
||||
|
|
|
@ -115,7 +115,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
thumbnailDownloadFailed:thumbnailDownloadFailed];
|
||||
}
|
||||
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(ConversationViewItem *)conversationItem
|
||||
+ (nullable instancetype)quotedReplyForSendingWithConversationViewItem:(id<ConversationViewItem>)conversationItem
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
{
|
||||
OWSAssertDebug(conversationItem);
|
||||
|
|
Loading…
Reference in New Issue