Decompose MessagesViewController, add “scroll to bottom button”, improve scrolling behavior.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 6db853103d
commit 22fc69bbb4

@ -6,6 +6,7 @@
#import <MediaPlayer/MediaPlayer.h> #import <MediaPlayer/MediaPlayer.h>
#import <JSQMessagesViewController/JSQMessagesViewController.h> #import <JSQMessagesViewController/JSQMessagesViewController.h>
#import "TSGroupModel.h" #import "TSGroupModel.h"
@class TSThread; @class TSThread;
extern NSString *const OWSMessagesViewControllerDidAppearNotification; extern NSString *const OWSMessagesViewControllerDidAppearNotification;
@ -28,18 +29,14 @@ extern NSString *const OWSMessagesViewControllerDidAppearNotification;
#pragma mark - #pragma mark -
@interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate, @interface MessagesViewController : JSQMessagesViewController
UINavigationControllerDelegate,
UITextViewDelegate,
AVAudioPlayerDelegate,
UIGestureRecognizerDelegate>
@property (nonatomic, readonly) TSThread *thread; @property (nonatomic, readonly) TSThread *thread;
- (void)configureForThread:(TSThread *)thread - (void)configureForThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardAppearing keyboardOnViewAppearing:(BOOL)keyboardAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing; callOnViewAppearing:(BOOL)callOnViewAppearing;
- (void)popKeyBoard; - (void)popKeyBoard;
#pragma mark 3D Touch Methods #pragma mark 3D Touch Methods

File diff suppressed because it is too large Load Diff

@ -2,19 +2,19 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// //
@class TSThread; NS_ASSUME_NONNULL_BEGIN
@class OWSBlockingManager;
@class OWSContactsManager;
@class OWSMessageSender; @class OWSMessageSender;
@class SignalAttachment; @class SignalAttachment;
@class TSContactThread; @class TSContactThread;
@class TSInteraction;
@class TSStorageManager; @class TSStorageManager;
@class OWSContactsManager; @class TSThread;
@class OWSBlockingManager;
NS_ASSUME_NONNULL_BEGIN
@class TSUnreadIndicatorInteraction; @class TSUnreadIndicatorInteraction;
@interface ThreadOffersAndIndicators : NSObject @interface ThreadDynamicInteractions : NSObject
// If there are unseen messages in the thread, this is the index // If there are unseen messages in the thread, this is the index
// of the unseen indicator, counting from the _end_ of the conversation // of the unseen indicator, counting from the _end_ of the conversation
@ -30,23 +30,27 @@ NS_ASSUME_NONNULL_BEGIN
// //
// Once we enter messages view, we mark all messages read, so we need // Once we enter messages view, we mark all messages read, so we need
// a snapshot of what the first unread message was when we entered the // a snapshot of what the first unread message was when we entered the
// view so that we can call ensureThreadOffersAndIndicators:... // view so that we can call ensureDynamicInteractionsForThread:...
// repeatedly. The unread indicator should continue to show up until // repeatedly. The unread indicator should continue to show up until
// it has been cleared, at which point hideUnreadMessagesIndicator is // it has been cleared, at which point hideUnreadMessagesIndicator is
// YES in ensureThreadOffersAndIndicators:... // YES in ensureDynamicInteractionsForThread:...
@property (nonatomic, nullable) NSNumber *firstUnseenInteractionTimestamp; @property (nonatomic, nullable) NSNumber *firstUnseenInteractionTimestamp;
- (void)clearUnreadIndicatorState;
@end @end
#pragma mark - #pragma mark -
@class TSOutgoingMessage;
@interface ThreadUtil : NSObject @interface ThreadUtil : NSObject
+ (void)sendMessageWithText:(NSString *)text + (TSOutgoingMessage *)sendMessageWithText:(NSString *)text
inThread:(TSThread *)thread inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender; messageSender:(OWSMessageSender *)messageSender;
+ (void)sendMessageWithAttachment:(SignalAttachment *)attachment + (TSOutgoingMessage *)sendMessageWithAttachment:(SignalAttachment *)attachment
inThread:(TSThread *)thread inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender; messageSender:(OWSMessageSender *)messageSender;
@ -68,7 +72,7 @@ NS_ASSUME_NONNULL_BEGIN
// slow and unwieldy. This number represents the maximum current // slow and unwieldy. This number represents the maximum current
// size of the "load window" in that view. The unread indicator should // size of the "load window" in that view. The unread indicator should
// always be inserted within that window. // always be inserted within that window.
+ (ThreadOffersAndIndicators *)ensureThreadOffersAndIndicators:(TSThread *)thread + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread
storageManager:(TSStorageManager *)storageManager storageManager:(TSStorageManager *)storageManager
contactsManager:(OWSContactsManager *)contactsManager contactsManager:(OWSContactsManager *)contactsManager
blockingManager:(OWSBlockingManager *)blockingManager blockingManager:(OWSBlockingManager *)blockingManager

@ -18,7 +18,13 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@implementation ThreadOffersAndIndicators @implementation ThreadDynamicInteractions
- (void)clearUnreadIndicatorState
{
self.unreadIndicatorPosition = nil;
self.firstUnseenInteractionTimestamp = nil;
}
@end @end
@ -26,7 +32,9 @@ NS_ASSUME_NONNULL_BEGIN
@implementation ThreadUtil @implementation ThreadUtil
+ (void)sendMessageWithText:(NSString *)text inThread:(TSThread *)thread messageSender:(OWSMessageSender *)messageSender + (TSOutgoingMessage *)sendMessageWithText:(NSString *)text
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender
{ {
OWSAssert([NSThread isMainThread]); OWSAssert([NSThread isMainThread]);
OWSAssert(text.length > 0); OWSAssert(text.length > 0);
@ -48,10 +56,12 @@ NS_ASSUME_NONNULL_BEGIN
failure:^(NSError *error) { failure:^(NSError *error) {
DDLogWarn(@"%@ Failed to deliver message with error: %@", self.tag, error); DDLogWarn(@"%@ Failed to deliver message with error: %@", self.tag, error);
}]; }];
return message;
} }
+ (void)sendMessageWithAttachment:(SignalAttachment *)attachment + (TSOutgoingMessage *)sendMessageWithAttachment:(SignalAttachment *)attachment
inThread:(TSThread *)thread inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender messageSender:(OWSMessageSender *)messageSender
{ {
@ -79,9 +89,11 @@ NS_ASSUME_NONNULL_BEGIN
failure:^(NSError *error) { failure:^(NSError *error) {
DDLogError(@"%@ Failed to send message attachment with error: %@", self.tag, error); DDLogError(@"%@ Failed to send message attachment with error: %@", self.tag, error);
}]; }];
return message;
} }
+ (ThreadOffersAndIndicators *)ensureThreadOffersAndIndicators:(TSThread *)thread + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread
storageManager:(TSStorageManager *)storageManager storageManager:(TSStorageManager *)storageManager
contactsManager:(OWSContactsManager *)contactsManager contactsManager:(OWSContactsManager *)contactsManager
blockingManager:(OWSBlockingManager *)blockingManager blockingManager:(OWSBlockingManager *)blockingManager
@ -96,7 +108,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(blockingManager); OWSAssert(blockingManager);
OWSAssert(maxRangeSize > 0); OWSAssert(maxRangeSize > 0);
ThreadOffersAndIndicators *result = [ThreadOffersAndIndicators new]; ThreadDynamicInteractions *result = [ThreadDynamicInteractions new];
[storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
const int kMaxBlockOfferOutgoingMessageCount = 10; const int kMaxBlockOfferOutgoingMessageCount = 10;
@ -141,7 +153,7 @@ NS_ASSUME_NONNULL_BEGIN
} else if ([object isKindOfClass:[TSErrorMessage class]]) { } else if ([object isKindOfClass:[TSErrorMessage class]]) {
TSErrorMessage *errorMessage = (TSErrorMessage *)object; TSErrorMessage *errorMessage = (TSErrorMessage *)object;
OWSAssert(errorMessage.errorType == TSErrorMessageNonBlockingIdentityChange); OWSAssert(errorMessage.errorType == TSErrorMessageNonBlockingIdentityChange);
[nonBlockingSafetyNumberChanges addObject:object]; [nonBlockingSafetyNumberChanges addObject:errorMessage];
} else { } else {
DDLogError(@"Unexpected interaction type: %@", [object class]); DDLogError(@"Unexpected interaction type: %@", [object class]);
OWSAssert(0); OWSAssert(0);
@ -165,6 +177,7 @@ NS_ASSUME_NONNULL_BEGIN
firstUnseenInteractionTimestamp = @(firstUnseenInteraction.timestampForSorting); firstUnseenInteractionTimestamp = @(firstUnseenInteraction.timestampForSorting);
} }
} }
result.firstUnseenInteractionTimestamp = firstUnseenInteractionTimestamp;
TSIncomingMessage *firstIncomingMessage = TSIncomingMessage *firstIncomingMessage =
[[transaction ext:TSThreadIncomingMessageDatabaseViewExtensionName] firstObjectInGroup:thread.uniqueId]; [[transaction ext:TSThreadIncomingMessageDatabaseViewExtensionName] firstObjectInGroup:thread.uniqueId];
@ -183,7 +196,7 @@ NS_ASSUME_NONNULL_BEGIN
__block BOOL hasMoreUnseenMessages = NO; __block BOOL hasMoreUnseenMessages = NO;
__block TSInteraction *interactionAfterUnreadIndicator = nil; __block TSInteraction *interactionAfterUnreadIndicator = nil;
NSUInteger missingUnseenSafetyNumberChangeCount = 0; NSUInteger missingUnseenSafetyNumberChangeCount = 0;
if (firstUnseenInteractionTimestamp) { if (firstUnseenInteractionTimestamp != nil) {
[[transaction ext:TSMessageDatabaseViewExtensionName] [[transaction ext:TSMessageDatabaseViewExtensionName]
enumerateRowsInGroup:thread.uniqueId enumerateRowsInGroup:thread.uniqueId
withOptions:NSEnumerationReverse withOptions:NSEnumerationReverse
@ -199,13 +212,13 @@ NS_ASSUME_NONNULL_BEGIN
return; return;
} }
if ([object isKindOfClass:[TSUnreadIndicatorInteraction class]]) { TSInteraction *interaction = (TSInteraction *)object;
// Ignore existing unread indicator, if any.
if (interaction.isDynamicInteraction) {
// Ignore dynamic interactions, if any.
return; return;
} }
TSInteraction *interaction = (TSInteraction *)object;
if (interaction.timestampForSorting if (interaction.timestampForSorting
< firstUnseenInteractionTimestamp.unsignedLongLongValue) { < firstUnseenInteractionTimestamp.unsignedLongLongValue) {
// By default we want the unread indicator to appear just before // By default we want the unread indicator to appear just before
@ -251,7 +264,6 @@ NS_ASSUME_NONNULL_BEGIN
= (missingUnseenSafetyNumberChanges.count + nonBlockingSafetyNumberChanges.count); = (missingUnseenSafetyNumberChanges.count + nonBlockingSafetyNumberChanges.count);
} }
} }
result.firstUnseenInteractionTimestamp = firstUnseenInteractionTimestamp;
if (hasMoreUnseenMessages) { if (hasMoreUnseenMessages) {
// The unread indicator is _before_ the last visible unseen message. // The unread indicator is _before_ the last visible unseen message.
result.unreadIndicatorPosition = @(visibleUnseenMessageCount); result.unreadIndicatorPosition = @(visibleUnseenMessageCount);

Loading…
Cancel
Save