Resize conversation view cells as necessary.

// FREEBIE
This commit is contained in:
Matthew Chen 2017-10-11 15:23:53 -04:00
parent f7bd813c9f
commit 227fd5280d
14 changed files with 93 additions and 58 deletions

View file

@ -220,7 +220,7 @@ NS_ASSUME_NONNULL_BEGIN
filename = [[self.attachmentStream filePath] lastPathComponent];
}
NSString *topText = [[filename stringByDeletingPathExtension]
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (topText.length < 1) {
topText = [MIMETypeUtil fileExtensionForMIMEType:self.attachmentStream.contentType].uppercaseString;
}

View file

@ -56,11 +56,8 @@ NS_ASSUME_NONNULL_BEGIN
{
OWSAssert(!self.textLabel);
// [self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.layoutMargins = UIEdgeInsetsZero;
self.contentView.backgroundColor = [UIColor whiteColor];
self.payloadView = [UIView containerView];
[self.contentView addSubview:self.payloadView];

View file

@ -121,7 +121,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)trimmedText
{
return [self.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [self.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
// TODO:

View file

@ -2769,7 +2769,10 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
return;
}
[self reloadViewItems];
NSMutableSet<NSNumber *> *rowsThatChangedSize = [[self reloadViewItems] mutableCopy];
for (NSNumber *row in rowsThatChangedSize) {
DDLogError(@"might reload: %@", row);
}
BOOL wasAtBottom = [self isScrolledToBottom];
// We want sending messages to feel snappy. So, if the only
@ -2783,35 +2786,23 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
__block BOOL scrollToBottom = wasAtBottom;
[self.collectionView performBatchUpdates:^{
// TODO: We need to reload neighbords of changed cells.
void (^reloadNeighbors)(NSIndexPath *) = ^(NSIndexPath *indexPath) {
// if (indexPath.row > 0) {
// [self.collectionView reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:indexPath.row
// - 1
// inSection:0] ]];
// }
// if (indexPath.row + 1 < (NSInteger) self.viewItems.count) {
// [self.collectionView reloadItemsAtIndexPaths:@[ [NSIndexPath indexPathForRow:indexPath.row
// + 1
// inSection:0] ]];
// }
};
for (YapDatabaseViewRowChange *rowChange in messageRowChanges) {
switch (rowChange.type) {
case YapDatabaseViewChangeDelete: {
DDLogError(@".... YapDatabaseViewChangeDelete: %@", rowChange.collectionKey);
DDLogError(
@".... YapDatabaseViewChangeDelete: %@, %@", rowChange.collectionKey, rowChange.indexPath);
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath ]];
[rowsThatChangedSize removeObject:@(rowChange.indexPath.row)];
YapCollectionKey *collectionKey = rowChange.collectionKey;
OWSAssert(collectionKey.key.length > 0);
reloadNeighbors(rowChange.indexPath);
break;
}
case YapDatabaseViewChangeInsert: {
DDLogError(@".... YapDatabaseViewChangeInsert: %@", rowChange.collectionKey);
DDLogError(
@".... YapDatabaseViewChangeInsert: %@, %@", rowChange.collectionKey, rowChange.newIndexPath);
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
[rowsThatChangedSize removeObject:@(rowChange.newIndexPath.row)];
TSInteraction *interaction = [self interactionAtIndexPath:rowChange.newIndexPath];
if ([interaction isKindOfClass:[TSOutgoingMessage class]]) {
@ -2821,19 +2812,20 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
shouldAnimateScrollToBottom = NO;
}
}
reloadNeighbors(rowChange.newIndexPath);
break;
}
case YapDatabaseViewChangeMove: {
DDLogError(@".... YapDatabaseViewChangeMove: %@", rowChange.collectionKey);
DDLogError(@".... YapDatabaseViewChangeMove: %@, %@, %@",
rowChange.collectionKey,
rowChange.indexPath,
rowChange.newIndexPath);
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath ]];
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
reloadNeighbors(rowChange.indexPath);
reloadNeighbors(rowChange.newIndexPath);
break;
}
case YapDatabaseViewChangeUpdate: {
DDLogError(@".... YapDatabaseViewChangeUpdate: %@", rowChange.collectionKey);
DDLogError(
@".... YapDatabaseViewChangeUpdate: %@, %@", rowChange.collectionKey, rowChange.indexPath);
YapCollectionKey *collectionKey = rowChange.collectionKey;
OWSAssert(collectionKey.key.length > 0);
if (collectionKey.key) {
@ -2841,11 +2833,19 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
[self reloadViewItem:viewItem];
}
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
reloadNeighbors(rowChange.indexPath);
[rowsThatChangedSize removeObject:@(rowChange.indexPath.row)];
break;
}
}
}
// The changes performed above may affect the size of neighboring cells,
// as they may affect which cells show "date" headers or "status" footers.
NSMutableArray<NSIndexPath *> *rowsToReload = [NSMutableArray new];
for (NSNumber *row in rowsThatChangedSize) {
[rowsToReload addObject:[NSIndexPath indexPathForRow:row.integerValue inSection:0]];
}
[self.collectionView reloadItemsAtIndexPaths:rowsToReload];
}
completion:^(BOOL success) {
OWSAssert([NSThread isMainThread]);
@ -3595,7 +3595,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
return;
}
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (text.length < 1) {
return;
@ -3810,7 +3810,11 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
// This is a key method. It builds or rebuilds the list of
// cell view models.
- (void)reloadViewItems
//
// Returns a list of the rows which may have changed size and
// need to be reloaded if we're doing an incremental update
// of the view.
- (NSSet<NSNumber *> *)reloadViewItems
{
NSMutableArray<ConversationViewItem *> *viewItems = [NSMutableArray new];
NSMutableDictionary<NSString *, ConversationViewItem *> *viewItemMap = [NSMutableDictionary new];
@ -3828,29 +3832,46 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
OWSAssert(interaction);
ConversationViewItem *_Nullable viewItem = self.viewItemMap[interaction.uniqueId];
if (!viewItem) {
if (viewItem) {
viewItem.lastRow = viewItem.row;
} else {
viewItem = [[ConversationViewItem alloc] initWithTSInteraction:interaction];
}
viewItem.row = (NSInteger)row;
[viewItems addObject:viewItem];
OWSAssert(!viewItemMap[interaction.uniqueId]);
viewItemMap[interaction.uniqueId] = viewItem;
}
}];
NSMutableSet<NSNumber *> *rowsThatChangedSize = [NSMutableSet new];
// Update the "shouldShowDate" property of the view items.
int row = 0;
BOOL shouldShowDateOnNextViewItem = NO;
BOOL shouldShowDateOnNextViewItem = YES;
uint64_t previousViewItemTimestamp = 0;
for (ConversationViewItem *viewItem in viewItems) {
if (row == 0) {
viewItem.shouldShowDate = YES;
shouldShowDateOnNextViewItem = NO;
} else if (viewItem.interaction.interactionType == OWSInteractionType_UnreadIndicator
|| viewItem.interaction.interactionType == OWSInteractionType_Offer) {
viewItem.shouldShowDate = NO;
BOOL canShowDate = NO;
switch (viewItem.interaction.interactionType) {
case OWSInteractionType_Unknown:
case OWSInteractionType_UnreadIndicator:
case OWSInteractionType_Offer:
canShowDate = NO;
break;
case OWSInteractionType_IncomingMessage:
case OWSInteractionType_OutgoingMessage:
case OWSInteractionType_Error:
case OWSInteractionType_Info:
case OWSInteractionType_Call:
canShowDate = YES;
break;
}
BOOL shouldShowDate = NO;
if (!canShowDate) {
shouldShowDate = NO;
shouldShowDateOnNextViewItem = YES;
} else if (shouldShowDateOnNextViewItem) {
viewItem.shouldShowDate = YES;
shouldShowDate = YES;
shouldShowDateOnNextViewItem = NO;
} else {
uint64_t viewItemTimestamp = viewItem.interaction.timestampForSorting;
@ -3859,16 +3880,26 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
uint64_t timeDifferenceMs = viewItemTimestamp - previousViewItemTimestamp;
static const uint64_t kShowTimeIntervalMs = 5 * kMinuteInMs;
if (timeDifferenceMs > kShowTimeIntervalMs) {
viewItem.shouldShowDate = YES;
shouldShowDate = YES;
}
shouldShowDateOnNextViewItem = NO;
}
if (viewItem.shouldShowDate != shouldShowDate) {
// If this is an existing view item and it has changed size,
// note that so that we can reload this cell while doing
// incremental updates.
if (viewItem.lastRow != NSNotFound) {
[rowsThatChangedSize addObject:@(viewItem.lastRow)];
}
}
viewItem.shouldShowDate = shouldShowDate;
previousViewItemTimestamp = viewItem.interaction.timestampForSorting;
row++;
}
self.viewItems = viewItems;
self.viewItemMap = viewItemMap;
return [rowsThatChangedSize copy];
}
// Whenever an interaction is modified, we need to reload it from the DB

View file

@ -41,6 +41,9 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
@property (nonatomic) BOOL shouldShowDate;
@property (nonatomic) NSInteger row;
@property (nonatomic) NSInteger lastRow;
//@property (nonatomic, weak) ConversationViewCell *lastCell;
- (instancetype)init NS_UNAVAILABLE;

View file

@ -70,6 +70,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
}
_interaction = interaction;
self.row = NSNotFound;
self.lastRow = NSNotFound;
return self;
}
@ -265,13 +267,14 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
if (!displayableText) {
// Only show up to 2kb of text.
const NSUInteger kMaxTextDisplayLength = 2 * 1024;
text = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
displayableText = [[DisplayableTextFilter new] displayableText:text];
if (displayableText.length > kMaxTextDisplayLength) {
// Trim whitespace before _AND_ after slicing the snipper from the string.
NSString *snippet =
[[[displayableText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
[[[displayableText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
substringWithRange:NSMakeRange(0, kMaxTextDisplayLength)]
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
displayableText = [NSString stringWithFormat:NSLocalizedString(@"OVERSIZE_TEXT_DISPLAY_FORMAT",
@"A display format for oversize text messages."),
snippet];

View file

@ -143,7 +143,7 @@
- (void)searchTextDidChange
{
NSString *searchText =
[self.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[self.searchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.countryCodes = [PhoneNumberUtil countryCodesForSearchTerm:searchText];

View file

@ -515,8 +515,8 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
- (TSGroupModel *)makeGroup
{
NSString *groupName =
[self.groupNameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *groupName = [self.groupNameTextField.text
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableArray<NSString *> *recipientIds = [self.memberRecipientIds.allObjects mutableCopy];
[recipientIds addObject:[self.contactsViewHelper localNumber]];
NSData *groupId = [SecurityUtils generateRandomBytes:16];

View file

@ -410,7 +410,7 @@ NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDat
- (NSString *)normalizedProfileName
{
return [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void)updateProfileCompleted

View file

@ -281,7 +281,7 @@ NSString *const kKeychainKey_LastRegisteredPhoneNumber = @"kKeychainKey_LastRegi
- (void)sendCodeAction
{
NSString *phoneNumberText =
[_phoneNumberTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[_phoneNumberTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (phoneNumberText.length < 1) {
[OWSAlerts
showAlertWithTitle:NSLocalizedString(@"REGISTRATION_VIEW_NO_PHONE_NUMBER_ALERT_TITLE",

View file

@ -196,8 +196,8 @@ NS_ASSUME_NONNULL_BEGIN
UITextField *groupNameTextField = [UITextField new];
_groupNameTextField = groupNameTextField;
self.groupNameTextField.text =
[self.thread.groupModel.groupName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
self.groupNameTextField.text = [self.thread.groupModel.groupName
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
groupNameTextField.textColor = [UIColor blackColor];
groupNameTextField.font = [UIFont ows_dynamicTypeTitle2Font];
groupNameTextField.placeholder
@ -373,8 +373,8 @@ NS_ASSUME_NONNULL_BEGIN
{
OWSAssert(self.conversationSettingsViewDelegate);
NSString *groupName =
[self.groupNameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *groupName = [self.groupNameTextField.text
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
TSGroupModel *groupModel = [[TSGroupModel alloc] initWithTitle:groupName
memberIds:[self.memberRecipientIds.allObjects mutableCopy]
image:self.groupAvatar

View file

@ -272,7 +272,8 @@ NSString *const kNotificationsManagerNewMesssageSoundName = @"NewMessage.aifc";
BOOL shouldPlaySound = [self shouldPlaySoundForNotification];
NSString *senderName = [contactsManager displayNameForPhoneIdentifier:message.authorId];
NSString *groupName = [thread.name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSString *groupName =
[thread.name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (groupName.length < 1) {
groupName = [MessageStrings newGroupDefaultTitle];
}

View file

@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)ows_stripped
{
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView

View file

@ -136,7 +136,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)trimName:(NSString *)name
{
return [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
+ (NSString *)uniqueIdFromABRecordId:(ABRecordID)recordId