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

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

@ -6,6 +6,7 @@
#import <MediaPlayer/MediaPlayer.h>
#import <JSQMessagesViewController/JSQMessagesViewController.h>
#import "TSGroupModel.h"
@class TSThread;
extern NSString *const OWSMessagesViewControllerDidAppearNotification;
@ -28,18 +29,14 @@ extern NSString *const OWSMessagesViewControllerDidAppearNotification;
#pragma mark -
@interface MessagesViewController : JSQMessagesViewController <UIImagePickerControllerDelegate,
UINavigationControllerDelegate,
UITextViewDelegate,
AVAudioPlayerDelegate,
UIGestureRecognizerDelegate>
@interface MessagesViewController : JSQMessagesViewController
@property (nonatomic, readonly) TSThread *thread;
- (void)configureForThread:(TSThread *)thread
keyboardOnViewAppearing:(BOOL)keyboardAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing;
- (void)popKeyBoard;
#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.
//
@class TSThread;
NS_ASSUME_NONNULL_BEGIN
@class OWSBlockingManager;
@class OWSContactsManager;
@class OWSMessageSender;
@class SignalAttachment;
@class TSContactThread;
@class TSInteraction;
@class TSStorageManager;
@class OWSContactsManager;
@class OWSBlockingManager;
NS_ASSUME_NONNULL_BEGIN
@class TSThread;
@class TSUnreadIndicatorInteraction;
@interface ThreadOffersAndIndicators : NSObject
@interface ThreadDynamicInteractions : NSObject
// If there are unseen messages in the thread, this is the index
// of the unseen indicator, counting from the _end_ of the conversation
@ -30,25 +30,29 @@ NS_ASSUME_NONNULL_BEGIN
//
// 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
// view so that we can call ensureThreadOffersAndIndicators:...
// view so that we can call ensureDynamicInteractionsForThread:...
// repeatedly. The unread indicator should continue to show up until
// it has been cleared, at which point hideUnreadMessagesIndicator is
// YES in ensureThreadOffersAndIndicators:...
// YES in ensureDynamicInteractionsForThread:...
@property (nonatomic, nullable) NSNumber *firstUnseenInteractionTimestamp;
- (void)clearUnreadIndicatorState;
@end
#pragma mark -
@class TSOutgoingMessage;
@interface ThreadUtil : NSObject
+ (void)sendMessageWithText:(NSString *)text
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender;
+ (TSOutgoingMessage *)sendMessageWithText:(NSString *)text
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender;
+ (void)sendMessageWithAttachment:(SignalAttachment *)attachment
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender;
+ (TSOutgoingMessage *)sendMessageWithAttachment:(SignalAttachment *)attachment
inThread:(TSThread *)thread
messageSender:(OWSMessageSender *)messageSender;
// This method will create and/or remove any offers and indicators
// necessary for this thread. This includes:
@ -68,13 +72,13 @@ NS_ASSUME_NONNULL_BEGIN
// slow and unwieldy. This number represents the maximum current
// size of the "load window" in that view. The unread indicator should
// always be inserted within that window.
+ (ThreadOffersAndIndicators *)ensureThreadOffersAndIndicators:(TSThread *)thread
storageManager:(TSStorageManager *)storageManager
contactsManager:(OWSContactsManager *)contactsManager
blockingManager:(OWSBlockingManager *)blockingManager
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp
maxRangeSize:(int)maxRangeSize;
+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread
storageManager:(TSStorageManager *)storageManager
contactsManager:(OWSContactsManager *)contactsManager
blockingManager:(OWSBlockingManager *)blockingManager
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp
maxRangeSize:(int)maxRangeSize;
@end

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

Loading…
Cancel
Save