From 5cc11b90149d15ce77d19af8b985a0bc961d0407 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 5 May 2020 09:11:43 +1000 Subject: [PATCH 1/2] Partially fix friend request UI issues --- .../Loki/Components/FriendRequestView.swift | 4 +- .../ConversationView/Cells/OWSMessageCell.m | 2 + .../ConversationViewController.m | 59 +++++++++++-------- .../ConversationView/ConversationViewModel.h | 2 + SignalMessaging/utils/ThreadUtil.m | 11 ---- SignalServiceKit/src/Contacts/TSThread.h | 4 +- SignalServiceKit/src/Contacts/TSThread.m | 17 +++--- .../src/Messages/Interactions/TSMessage.h | 1 + .../src/Messages/Interactions/TSMessage.m | 6 +- 9 files changed, 58 insertions(+), 48 deletions(-) diff --git a/Signal/src/Loki/Components/FriendRequestView.swift b/Signal/src/Loki/Components/FriendRequestView.swift index f662b1ed4..750dd886e 100644 --- a/Signal/src/Loki/Components/FriendRequestView.swift +++ b/Signal/src/Loki/Components/FriendRequestView.swift @@ -106,7 +106,7 @@ final class FriendRequestView : UIView { updateUI() } - private func updateUI() { + @objc public func updateUI() { let thread = message.thread let friendRequestStatus = FriendRequestProtocol.getFriendRequestUIStatus(for: thread) guard let contactID = thread.contactIdentifier() else { return } @@ -127,7 +127,7 @@ final class FriendRequestView : UIView { switch friendRequestStatus { case .none: format = nil // The message failed to send case .friends: format = nil - case .received: return + case .received: return // Should never occur case .sent: format = NSLocalizedString("You've sent %@ a session request", comment: "") case .expired: format = NSLocalizedString("Your session request to %@ has expired", comment: "") } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index b541c1771..8609fe9b8 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -225,6 +225,8 @@ NS_ASSUME_NONNULL_BEGIN [self.friendRequestView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.messageBubbleView], [self.friendRequestView autoPinEdgeToSuperviewEdge:ALEdgeBottom] ]]; + } else { + [self.friendRequestView removeFromSuperview]; } if ([self updateAvatarView]) { diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 9a83e0c9e..fce608bd0 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -518,7 +518,6 @@ typedef enum : NSUInteger { - (void)handleGroupThreadUpdatedNotification:(NSNotification *)notification { OWSAssertIsOnMainThread(); - // Check thread NSString *threadID = (NSString *)notification.object; if (![threadID isEqualToString:self.thread.uniqueId]) { return; } @@ -526,29 +525,34 @@ typedef enum : NSUInteger { [self.thread reload]; // Update UI [self hideInputIfNeeded]; - [self resetContentAndLayout]; + [self.collectionView.collectionViewLayout invalidateLayout]; + for (id item in self.viewItems) { + [item clearCachedLayoutState]; + } + [self.conversationViewModel reloadViewItems]; + [self.collectionView reloadData]; } - (void)handleUserFriendRequestStatusChangedNotification:(NSNotification *)notification { + OWSAssertIsOnMainThread(); // Friend request status doesn't apply to group threads if (self.thread.isGroupThread) { return; } NSString *hexEncodedPublicKey = (NSString *)notification.object; // Check if we should update the UI - __block BOOL needsUpdate; + __block NSSet *linkedDevices; [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - NSSet *linkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:self.thread.contactIdentifier in:transaction]; - needsUpdate = [linkedDevices containsObject:hexEncodedPublicKey]; + linkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:self.thread.contactIdentifier in:transaction]; }]; - if (!needsUpdate) { return; } - // Ensure the thread instance is up to date - [self.thread reload]; + if (![linkedDevices containsObject:hexEncodedPublicKey]) { return; } // Update the UI + [self updateInputBar]; + [self.collectionView.collectionViewLayout invalidateLayout]; for (id item in self.viewItems) { [item clearCachedLayoutState]; } - [self updateInputToolbar]; - [self resetContentAndLayout]; + [self.conversationViewModel reloadViewItems]; + [self.collectionView reloadData]; } - (void)handleThreadSessionRestoreDevicesChangedNotifiaction:(NSNotification *)notification @@ -665,6 +669,7 @@ typedef enum : NSUInteger { self.inputToolbar.hidden = NO; } + // Loki: In RSS feeds, don't hide the input bar entirely; just hide the text field inside. if (self.isRSSFeed) { [self.inputToolbar hideInputMethod]; } @@ -780,7 +785,7 @@ typedef enum : NSUInteger { self.inputToolbar.inputToolbarDelegate = self; self.inputToolbar.inputTextViewDelegate = self; SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _inputToolbar); - [self updateInputToolbar]; + [self updateInputBar]; self.loadMoreHeader = [UILabel new]; self.loadMoreHeader.text = NSLocalizedString(@"CONVERSATION_VIEW_LOADING_MORE_MESSAGES", @"Indicates that the app is loading more messages in this conversation."); @@ -921,7 +926,7 @@ typedef enum : NSUInteger { NSTimeInterval appearenceDuration = CACurrentMediaTime() - self.viewControllerCreatedAt; OWSLogVerbose(@"First viewWillAppear took: %.2fms", appearenceDuration * 1000); } - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; } - (NSArray> *)viewItems @@ -1048,7 +1053,7 @@ typedef enum : NSUInteger { - (void)updateSessionRestoreBanner { BOOL isContactThread = [self.thread isKindOfClass:[TSContactThread class]]; - BOOL shouldRemoveBanner = !isContactThread; + BOOL shouldDetachBanner = !isContactThread; if (isContactThread) { TSContactThread *thread = (TSContactThread *)self.thread; if (thread.sessionRestoreDevices.count > 0) { @@ -1068,11 +1073,10 @@ typedef enum : NSUInteger { }]; } } else { - shouldRemoveBanner = true; + shouldDetachBanner = true; } } - - if (shouldRemoveBanner && self.restoreSessionBannerView) { + if (shouldDetachBanner && self.restoreSessionBannerView != nil) { [self.restoreSessionBannerView removeFromSuperview]; self.restoreSessionBannerView = nil; } @@ -1461,7 +1465,7 @@ typedef enum : NSUInteger { // Clear the "on open" state after the view has been presented. self.actionOnOpen = ConversationViewActionNone; - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; [self ensureScrollDownButton]; } @@ -1668,7 +1672,7 @@ typedef enum : NSUInteger { #pragma mark - Updating -- (void)updateInputToolbar { +- (void)updateInputBar { BOOL shouldInputBarBeEnabled = [LKFriendRequestProtocol shouldInputBarBeEnabledForThread:self.thread]; [self.inputToolbar setUserInteractionEnabled:shouldInputBarBeEnabled]; NSString *placeholderText = shouldInputBarBeEnabled ? NSLocalizedString(@"Message", "") : NSLocalizedString(@"Pending session request", ""); @@ -2890,6 +2894,15 @@ typedef enum : NSUInteger { AudioServicesPlaySystemSound(soundId); } [self.typingIndicators didSendOutgoingMessageInThread:self.thread]; + + // Loki: Lock the input bar early + if ([self.thread isKindOfClass:TSContactThread.class] && [message isKindOfClass:LKFriendRequestMessage.class]) { + NSString *recipientID = self.thread.contactIdentifier; + OWSAssertIsOnMainThread(); + [OWSPrimaryStorage.sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [LKFriendRequestProtocol setFriendRequestStatusToSendingIfNeededForHexEncodedPublicKey:recipientID transaction:transaction]; + }]; + } } #pragma mark UIDocumentMenuDelegate @@ -5086,7 +5099,7 @@ typedef enum : NSUInteger { } [self dismissMenuActionsIfNecessary]; - [self updateInputToolbar]; + [self updateInputBar]; if (self.isGroupConversation) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { @@ -5332,7 +5345,7 @@ typedef enum : NSUInteger { // new size. [strongSelf resetForSizeOrOrientationChange]; - [strongSelf updateInputToolbarLayout]; + [strongSelf updateInputBarLayout]; if (self.menuActionsViewController != nil) { [self scrollToMenuActionInteraction:NO]; @@ -5367,17 +5380,17 @@ typedef enum : NSUInteger { // Try to update the lastKnownDistanceFromBottom; the content size may have changed. [self updateLastKnownDistanceFromBottom]; } - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; } - (void)viewSafeAreaInsetsDidChange { [super viewSafeAreaInsetsDidChange]; - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; } -- (void)updateInputToolbarLayout +- (void)updateInputBarLayout { UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero; if (@available(iOS 11, *)) { diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h index 1b9c4d86a..daa28db23 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h @@ -123,6 +123,8 @@ typedef NS_ENUM(NSUInteger, ConversationUpdateItemType) { - (void)appendUnsavedOutgoingTextMessage:(TSOutgoingMessage *)outgoingMessage; +- (BOOL)reloadViewItems; + @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index d9dd7e10d..a1516c539 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -184,17 +184,6 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess // If we're friends then the assumption is that we have the other user's pre key bundle. NSString *messageClassAsString = (thread.isContactFriend || thread.isGroupThread || thread.isNoteToSelf) ? @"TSOutgoingMessage" : @"LKFriendRequestMessage"; Class messageClass = NSClassFromString(messageClassAsString); - - if ([messageClassAsString isEqual:@"LKFriendRequestMessage"]) { - NSString *recipientID = thread.contactIdentifier; - if (recipientID != nil) { - dispatch_async(dispatch_get_main_queue(), ^{ - [OWSPrimaryStorage.sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKFriendRequestProtocol setFriendRequestStatusToSendingIfNeededForHexEncodedPublicKey:recipientID transaction:transaction]; - }]; - }); - } - } TSOutgoingMessage *message = [[messageClass alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index daf08b30e..468031a0d 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -184,12 +184,12 @@ extern ConversationColorName const kConversationColorName_Default; #pragma mark - Loki Friend Request Handling /** - Remove any outgoing friend request message which failed to send + Remove any old outgoing friend request messages that failed to send. */ - (void)removeOldOutgoingFriendRequestMessagesIfNeededWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; /** - Remove any old incoming friend request message that is still pending + Remove any old incoming friend request messages that are pending. */ - (void)removeOldIncomingFriendRequestMessagesIfNeededWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 33571237a..3696e266a 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -722,12 +722,13 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa - (void)removeOldFriendRequestMessagesIfNeeded:(OWSInteractionType)interactionType withTransaction:(YapDatabaseReadWriteTransaction *)transaction { - // If we're friends with the person then we don't need to remove any friend request messages + // Friend request status doesn't apply to group threads if (self.isGroupThread) { return; } + // If we're friends with the other person then we don't need to remove any friend request messages if ([LKFriendRequestProtocol isFriendsWithAnyLinkedDeviceOfHexEncodedPublicKey:self.contactIdentifier]) { return; } NSMutableArray *idsToRemove = [NSMutableArray new]; - __block TSMessage *_Nullable messageToKeep = nil; // We want to keep this interaction and not remove it + __block TSMessage *_Nullable messageToKeep = nil; [self enumerateInteractionsWithTransaction:transaction usingBlock:^(TSInteraction *interaction, YapDatabaseReadTransaction *transaction) { if (interaction.interactionType != interactionType) { return; } @@ -754,14 +755,14 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa } }]; - for (NSString *interactionId in idsToRemove) { - // Don't delete the recent message - if (messageToKeep != nil && interactionId == messageToKeep.uniqueId) { continue; } + for (NSString *interactionID in idsToRemove) { + // Don't delete the most recent message + if (messageToKeep != nil && interactionID == messageToKeep.uniqueId) { continue; } // We need to fetch each interaction, since [TSInteraction removeWithTransaction:] does important work - TSInteraction *_Nullable interaction = [TSInteraction fetchObjectWithUniqueID:interactionId transaction:transaction]; - if (!interaction) { - OWSFailDebug(@"couldn't load thread's interaction for deletion."); + TSInteraction *_Nullable interaction = [TSInteraction fetchObjectWithUniqueID:interactionID transaction:transaction]; + if (interaction == nil) { + OWSFailDebug(@"Couldn't load interaction."); continue; } [interaction removeWithTransaction:transaction]; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.h b/SignalServiceKit/src/Messages/Interactions/TSMessage.h index bca04ac94..816bb67f9 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.h @@ -40,6 +40,7 @@ typedef NS_ENUM(NSInteger, LKMessageFriendRequestStatus) { @property (nonatomic, nullable) OWSLinkPreview *linkPreview; // Loki friend request handling @property (nonatomic) LKMessageFriendRequestStatus friendRequestStatus __deprecated_msg("no longer used as of version 1.1.2"); +/// Only relevant to outgoing messages. @property (nonatomic) uint64_t friendRequestExpiresAt; @property (nonatomic, readonly) BOOL isFriendRequest; @property (nonatomic, readonly) BOOL hasFriendRequestStatusMessage; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 272a78847..86a2a182f 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -475,13 +475,15 @@ static const NSUInteger OWSMessageSchemaVersion = 4; - (BOOL)isFriendRequest { - return [LKFriendRequestProtocol getFriendRequestUIStatusForThread:self.thread] != LKFriendRequestUIStatusFriends; + if (self.thread.isContactFriend) { return NO; } + return [self.uniqueId isEqual:self.thread.lastInteraction.uniqueId]; } - (BOOL)hasFriendRequestStatusMessage { LKFriendRequestUIStatus friendRequestStatus = [LKFriendRequestProtocol getFriendRequestUIStatusForThread:self.thread]; - return friendRequestStatus != LKFriendRequestUIStatusNone && friendRequestStatus != LKFriendRequestUIStatusFriends; + if (friendRequestStatus == LKFriendRequestUIStatusNone || friendRequestStatus == LKFriendRequestUIStatusFriends) { return NO; }; + return [self.uniqueId isEqual:self.thread.lastInteraction.uniqueId]; } #pragma mark - Open Groups From a9b3f3a6ca9c96beaa6d7c80965461d4ba331398 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 5 May 2020 09:32:20 +1000 Subject: [PATCH 2/2] Fix constraint issue --- .../src/ViewControllers/ConversationView/Cells/OWSMessageCell.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index 8609fe9b8..40cf4a619 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -227,6 +227,7 @@ NS_ASSUME_NONNULL_BEGIN ]]; } else { [self.friendRequestView removeFromSuperview]; + [self.messageBubbleViewBottomConstraint setActive:YES]; } if ([self updateAvatarView]) {