Merge pull request #479 from oxen-io/conversation-ui
Conversation Screen UI/UX Fixes
This commit is contained in:
commit
67e8191c2c
|
@ -169,6 +169,7 @@
|
|||
B8269D2925C7A4B400488AB4 /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8269D2825C7A4B400488AB4 /* InputView.swift */; };
|
||||
B8269D3325C7A8C600488AB4 /* InputViewButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8269D3225C7A8C600488AB4 /* InputViewButton.swift */; };
|
||||
B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8269D3C25C7B34D00488AB4 /* InputTextView.swift */; };
|
||||
B82A0C3826B9098200C1BCE3 /* MessageInvalidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */; };
|
||||
B82B40882399EB0E00A248E7 /* LandingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B40872399EB0E00A248E7 /* LandingVC.swift */; };
|
||||
B82B408A2399EC0600A248E7 /* FakeChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B40892399EC0600A248E7 /* FakeChatView.swift */; };
|
||||
B82B408C239A068800A248E7 /* RegisterVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82B408B239A068800A248E7 /* RegisterVC.swift */; };
|
||||
|
@ -1149,6 +1150,7 @@
|
|||
B8269D2825C7A4B400488AB4 /* InputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputView.swift; sourceTree = "<group>"; };
|
||||
B8269D3225C7A8C600488AB4 /* InputViewButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputViewButton.swift; sourceTree = "<group>"; };
|
||||
B8269D3C25C7B34D00488AB4 /* InputTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputTextView.swift; sourceTree = "<group>"; };
|
||||
B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageInvalidator.swift; sourceTree = "<group>"; };
|
||||
B82B40872399EB0E00A248E7 /* LandingVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingVC.swift; sourceTree = "<group>"; };
|
||||
B82B40892399EC0600A248E7 /* FakeChatView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeChatView.swift; sourceTree = "<group>"; };
|
||||
B82B408B239A068800A248E7 /* RegisterVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterVC.swift; sourceTree = "<group>"; };
|
||||
|
@ -3115,6 +3117,7 @@
|
|||
C33FDBC1255A581700E217F9 /* General.swift */,
|
||||
B8AE760925ABFB00001A84D2 /* GeneralUtilities.h */,
|
||||
B8AE760A25ABFB5A001A84D2 /* GeneralUtilities.m */,
|
||||
B82A0C3726B9098200C1BCE3 /* MessageInvalidator.swift */,
|
||||
C3A71D0A2558989C0043A11F /* MessageWrapper.swift */,
|
||||
C3A71D4E25589FF30043A11F /* NSData+messagePadding.h */,
|
||||
C3A71D4825589FF20043A11F /* NSData+messagePadding.m */,
|
||||
|
@ -4746,6 +4749,7 @@
|
|||
C32C5C01256DC9A0003C73A2 /* OWSIdentityManager.m in Sources */,
|
||||
C32C59C4256DB41F003C73A2 /* TSContactThread.m in Sources */,
|
||||
C32C5AB0256DBE8F003C73A2 /* TSOutgoingMessage.m in Sources */,
|
||||
B82A0C3826B9098200C1BCE3 /* MessageInvalidator.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -5063,7 +5067,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 286;
|
||||
CURRENT_PROJECT_VERSION = 287;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
|
@ -5132,7 +5136,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 286;
|
||||
CURRENT_PROJECT_VERSION = 287;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -5193,7 +5197,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 286;
|
||||
CURRENT_PROJECT_VERSION = 287;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
|
@ -5263,7 +5267,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 286;
|
||||
CURRENT_PROJECT_VERSION = 287;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -6148,7 +6152,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 286;
|
||||
CURRENT_PROJECT_VERSION = 287;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
@ -6216,7 +6220,7 @@
|
|||
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CURRENT_PROJECT_VERSION = 286;
|
||||
CURRENT_PROJECT_VERSION = 287;
|
||||
DEVELOPMENT_TEAM = SUQ8J2PCT7;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
|
|
|
@ -205,6 +205,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
notificationCenter.addObserver(self, selector: #selector(addOrRemoveBlockedBanner), name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange), object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(handleGroupUpdatedNotification), name: .groupThreadUpdated, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(sendScreenshotNotificationIfNeeded), name: UIApplication.userDidTakeScreenshotNotification, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(handleMessageSentStatusChanged), name: .messageSentStatusDidChange, object: nil)
|
||||
// Mentions
|
||||
MentionsManager.populateUserPublicKeyCacheIfNeeded(for: thread.uniqueId!)
|
||||
// Draft
|
||||
|
@ -319,13 +320,6 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
baselineKeyboardHeight = newHeight
|
||||
self.messagesTableView.keyboardHeight = newHeight
|
||||
}
|
||||
let margin = (self.lastPageTop - self.messagesTableView.contentOffset.y)
|
||||
// HACK: If the keyboard is coming up and we're very close to the bottom, scroll to the
|
||||
// bottom. This "fixes" an issue where the conversation would randomly scroll up sometimes
|
||||
// when bringing up the keyboard.
|
||||
if newHeight > 200 && margin <= 2 {
|
||||
scrollToBottom(isAnimated: false)
|
||||
}
|
||||
scrollButtonConstraint?.constant = -(newHeight + 16)
|
||||
let newContentOffsetY = max(self.messagesTableView.contentOffset.y + min(lastPageTop, 0) + newHeight - self.messagesTableView.keyboardHeight, 0.0)
|
||||
self.messagesTableView.contentOffset.y = newContentOffsetY
|
||||
|
@ -353,60 +347,34 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
return messagesTableView.reloadData()
|
||||
}
|
||||
var shouldScrollToBottom = false
|
||||
let shouldAnimate = conversationUpdate.shouldAnimateUpdates
|
||||
let batchUpdates: () -> Void = {
|
||||
for update in conversationUpdate.updateItems! {
|
||||
switch update.updateItemType {
|
||||
case .delete:
|
||||
self.messagesTableView.deleteRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .fade)
|
||||
self.messagesTableView.deleteRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .none)
|
||||
case .insert:
|
||||
// Perform inserts before updates
|
||||
self.messagesTableView.insertRows(at: [ IndexPath(row: Int(update.newIndex), section: 0) ], with: .fade)
|
||||
self.messagesTableView.insertRows(at: [ IndexPath(row: Int(update.newIndex), section: 0) ], with: .none)
|
||||
if update.viewItem?.interaction is TSOutgoingMessage {
|
||||
shouldScrollToBottom = true
|
||||
} else {
|
||||
shouldScrollToBottom = self.isCloseToBottom
|
||||
}
|
||||
case .update:
|
||||
self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .fade)
|
||||
shouldScrollToBottom = self.isCloseToBottom
|
||||
self.messagesTableView.reloadRows(at: [ IndexPath(row: Int(update.oldIndex), section: 0) ], with: .none)
|
||||
default: preconditionFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
let batchUpdatesCompletion: (Bool) -> Void = { isFinished in
|
||||
if shouldScrollToBottom {
|
||||
self.scrollToBottom(isAnimated: true)
|
||||
} else {
|
||||
// This is a workaround for an issue where after an attachment is sent without the keyboard showing before,
|
||||
// once the keyboard shows, the table view's content offset can be wrong and the last message won't completely show.
|
||||
// This is caused by the main run loop calling some table view update method that sets the content offset back to
|
||||
// the previous value when the keyboard is shown.
|
||||
self.messagesTableView.reloadData()
|
||||
}
|
||||
self.markAllAsRead()
|
||||
}
|
||||
if shouldAnimate {
|
||||
messagesTableView.performBatchUpdates(batchUpdates, completion: batchUpdatesCompletion)
|
||||
} else {
|
||||
// HACK: We use `UIView.animateWithDuration:0` rather than `UIView.performWithAnimation` to work around a
|
||||
// UIKit Crash like:
|
||||
//
|
||||
// *** Assertion failure in -[ConversationViewLayout prepareForCollectionViewUpdates:],
|
||||
// /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3600.7.47/UICollectionViewLayout.m:760
|
||||
// *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'While
|
||||
// preparing update a visible view at <NSIndexPath: 0xc000000011c00016> {length = 2, path = 0 - 142}
|
||||
// wasn't found in the current data model and was not in an update animation. This is an internal
|
||||
// error.'
|
||||
//
|
||||
// I'm unclear if this is a bug in UIKit, or if we're doing something crazy in
|
||||
// ConversationViewLayout#prepareLayout. To reproduce, rapidily insert and delete items into the
|
||||
// conversation.
|
||||
UIView.animate(withDuration: 0) {
|
||||
self.messagesTableView.performBatchUpdates(batchUpdates, completion: batchUpdatesCompletion)
|
||||
UIView.performWithoutAnimation {
|
||||
messagesTableView.performBatchUpdates(batchUpdates) { _ in
|
||||
if shouldScrollToBottom {
|
||||
self.scrollToBottom(isAnimated: false)
|
||||
}
|
||||
self.markAllAsRead()
|
||||
}
|
||||
if shouldScrollToBottom {
|
||||
self.scrollToBottom(isAnimated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -441,6 +409,24 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
reloadInputViews()
|
||||
}
|
||||
|
||||
@objc private func handleMessageSentStatusChanged() {
|
||||
DispatchQueue.main.async {
|
||||
guard let indexPaths = self.messagesTableView.indexPathsForVisibleRows else { return }
|
||||
var indexPathsToReload: [IndexPath] = []
|
||||
for indexPath in indexPaths {
|
||||
guard let cell = self.messagesTableView.cellForRow(at: indexPath) as? VisibleMessageCell else { continue }
|
||||
let isLast = (indexPath.item == (self.messagesTableView.numberOfRows(inSection: 0) - 1))
|
||||
guard !isLast else { continue }
|
||||
if !cell.messageStatusImageView.isHidden {
|
||||
indexPathsToReload.append(indexPath)
|
||||
}
|
||||
}
|
||||
UIView.performWithoutAnimation {
|
||||
self.messagesTableView.reloadRows(at: indexPathsToReload, with: .none)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: General
|
||||
@objc func addOrRemoveBlockedBanner() {
|
||||
func detach() {
|
||||
|
|
|
@ -822,9 +822,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSFailDebug(@"Can't find holdover view item.");
|
||||
return [self.delegate conversationViewModelDidUpdate:ConversationUpdate.reloadUpdate];
|
||||
}
|
||||
if (!viewItem.hasCachedLayoutState) {
|
||||
[updatedItemSet addObject:itemId];
|
||||
[updatedNeighborItemSet addObject:itemId];
|
||||
|
||||
if ([viewItem.interaction isKindOfClass:TSMessage.class]) {
|
||||
TSMessage *message = (TSMessage *)viewItem.interaction;
|
||||
if ([MessageInvalidator isInvalidated:message]) {
|
||||
[updatedItemSet addObject:itemId];
|
||||
[updatedNeighborItemSet addObject:itemId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -864,6 +868,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
oldViewItemCount:oldItemIdList.count
|
||||
updatedNeighborItemSet:updatedNeighborItemSet];
|
||||
|
||||
for (NSString *itemID in updatedItemSet) {
|
||||
[MessageInvalidator markAsUpdated:itemID];
|
||||
}
|
||||
|
||||
return [self.delegate
|
||||
conversationViewModelDidUpdate:[ConversationUpdate diffUpdateWithUpdateItems:updateItems
|
||||
shouldAnimateUpdates:shouldAnimateUpdates]];
|
||||
|
|
|
@ -81,7 +81,7 @@ final class VisibleMessageCell : MessageCell, LinkPreviewViewDelegate {
|
|||
|
||||
private lazy var snContentView = UIView()
|
||||
|
||||
private lazy var messageStatusImageView: UIImageView = {
|
||||
internal lazy var messageStatusImageView: UIImageView = {
|
||||
let result = UIImageView()
|
||||
result.contentMode = .scaleAspectFit
|
||||
result.layer.cornerRadius = VisibleMessageCell.messageStatusImageViewSize / 2
|
||||
|
|
|
@ -861,17 +861,6 @@ CGFloat kIconViewLength = 24;
|
|||
[self.thread updateWithMutedUntilDate:nil transaction:transaction];
|
||||
}];
|
||||
}
|
||||
if (self.isClosedGroup) {
|
||||
NSString *groupPublicKey = [LKGroupUtilities getDecodedGroupID:((TSGroupThread *)self.thread).groupModel.groupId];
|
||||
NSString *userPublicKey = [SNGeneralUtilities getUserPublicKey];
|
||||
if (uiSwitch.isOn) {
|
||||
[[LKPushNotificationAPI performOperation:ClosedGroupOperationUnsubscribe
|
||||
forClosedGroupWithPublicKey:groupPublicKey userPublicKey:userPublicKey] retainUntilComplete];
|
||||
} else {
|
||||
[[LKPushNotificationAPI performOperation:ClosedGroupOperationSubscribe
|
||||
forClosedGroupWithPublicKey:groupPublicKey userPublicKey:userPublicKey] retainUntilComplete];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blockConversationSwitchDidChange:(id)sender
|
||||
|
@ -1002,7 +991,7 @@ CGFloat kIconViewLength = 24;
|
|||
UISwitch *uiSwitch = (UISwitch *)sender;
|
||||
BOOL isEnabled = uiSwitch.isOn;
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[(TSGroupThread *)self.thread setisOnlyNotifyingForMentions:isEnabled withTransaction:transaction];
|
||||
[(TSGroupThread *)self.thread setIsOnlyNotifyingForMentions:isEnabled withTransaction:transaction];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ final class DownloadAttachmentModal : Modal {
|
|||
contact.isTrusted = true
|
||||
Storage.write(with: { transaction in
|
||||
Storage.shared.setContact(contact, using: transaction)
|
||||
message.touch(with: transaction)
|
||||
MessageInvalidator.invalidate(message, with: transaction)
|
||||
}, completion: {
|
||||
Storage.shared.resumeAttachmentDownloadJobsIfNeeded(for: message.uniqueThreadId)
|
||||
})
|
||||
|
|
|
@ -67,7 +67,7 @@ extension Storage {
|
|||
pointer.state = state
|
||||
pointer.save(with: transaction)
|
||||
guard let tsMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) else { return }
|
||||
tsMessage.touch(with: transaction)
|
||||
MessageInvalidator.invalidate(tsMessage, with: transaction)
|
||||
}
|
||||
|
||||
/// Also touches the associated message.
|
||||
|
@ -75,7 +75,7 @@ extension Storage {
|
|||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
stream.save(with: transaction)
|
||||
guard let tsMessage = TSMessage.fetch(uniqueId: tsMessageID, transaction: transaction) else { return }
|
||||
tsMessage.touch(with: transaction)
|
||||
MessageInvalidator.invalidate(tsMessage, with: transaction)
|
||||
}
|
||||
|
||||
private static let receivedMessageTimestampsCollection = "ReceivedMessageTimestampsCollection"
|
||||
|
|
|
@ -118,12 +118,14 @@ public final class AttachmentUploadJob : NSObject, Job, NSCoding { // NSObject/N
|
|||
delegate?.handleJobSucceeded(self)
|
||||
SNMessagingKitConfiguration.shared.storage.resumeMessageSendJobIfNeeded(messageSendJobID)
|
||||
Storage.shared.write(with: { transaction in
|
||||
var interaction: TSInteraction?
|
||||
var message: TSMessage?
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
TSDatabaseSecondaryIndexes.enumerateMessages(withTimestamp: self.message.sentTimestamp!, with: { _, key, _ in
|
||||
interaction = TSInteraction.fetch(uniqueId: key, transaction: transaction)
|
||||
message = TSMessage.fetch(uniqueId: key, transaction: transaction)
|
||||
}, using: transaction)
|
||||
interaction?.touch(with: transaction) // To refresh the associated message cell and hide the loader
|
||||
if let message = message {
|
||||
MessageInvalidator.invalidate(message, with: transaction)
|
||||
}
|
||||
}, completion: { })
|
||||
}
|
||||
|
||||
|
|
|
@ -330,7 +330,6 @@ public final class MessageSender : NSObject {
|
|||
if let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) {
|
||||
// Track the open group server message ID
|
||||
tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0
|
||||
tsMessage.save(with: transaction)
|
||||
// Mark the message as sent
|
||||
var recipients = [ message.recipient! ]
|
||||
if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point
|
||||
|
@ -340,6 +339,8 @@ public final class MessageSender : NSObject {
|
|||
recipients.forEach { recipient in
|
||||
tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction)
|
||||
}
|
||||
tsMessage.save(with: transaction)
|
||||
NotificationCenter.default.post(name: .messageSentStatusDidChange, object: nil, userInfo: nil)
|
||||
// Start the disappearing messages timer if needed
|
||||
OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction)
|
||||
}
|
||||
|
@ -358,6 +359,8 @@ public final class MessageSender : NSObject {
|
|||
|
||||
public static func handleFailedMessageSend(_ message: Message, with error: Swift.Error, using transaction: Any) {
|
||||
guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return }
|
||||
tsMessage.update(sendingError: error, transaction: transaction as! YapDatabaseReadWriteTransaction)
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
tsMessage.update(sendingError: error, transaction: transaction)
|
||||
MessageInvalidator.invalidate(tsMessage, with: transaction)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,13 +88,7 @@ public final class PushNotificationAPI : NSObject {
|
|||
}
|
||||
// Subscribe to all closed groups
|
||||
Storage.shared.getUserClosedGroupPublicKeys().forEach { closedGroupPublicKey in
|
||||
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(closedGroupPublicKey)
|
||||
let threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID))
|
||||
if threadOrNil?.isMuted == true {
|
||||
// Do nothing
|
||||
} else {
|
||||
performOperation(.subscribe, for: closedGroupPublicKey, publicKey: publicKey)
|
||||
}
|
||||
performOperation(.subscribe, for: closedGroupPublicKey, publicKey: publicKey)
|
||||
}
|
||||
return promise
|
||||
}
|
||||
|
|
|
@ -3,10 +3,12 @@ public extension Notification.Name {
|
|||
|
||||
static let groupThreadUpdated = Notification.Name("groupThreadUpdated")
|
||||
static let muteSettingUpdated = Notification.Name("muteSettingUpdated")
|
||||
static let messageSentStatusDidChange = Notification.Name("messageSentStatusDidChange")
|
||||
}
|
||||
|
||||
@objc public extension NSNotification {
|
||||
|
||||
@objc static let groupThreadUpdated = Notification.Name.groupThreadUpdated.rawValue as NSString
|
||||
@objc static let muteSettingUpdated = Notification.Name.muteSettingUpdated.rawValue as NSString
|
||||
@objc static let messageSentStatusDidChange = Notification.Name.messageSentStatusDidChange.rawValue as NSString
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId;
|
|||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
- (void)setGroupModel:(TSGroupModel *)newGroupModel withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)setisOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)setIsOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)leaveGroupWithSneakyTransaction;
|
||||
- (void)leaveGroupWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)setisOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
- (void)setIsOnlyNotifyingForMentions:(BOOL)isOnlyNotifyingForMentions withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
self.isOnlyNotifyingForMentions = isOnlyNotifyingForMentions;
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
/// A message is invalidated when it needs to be re-rendered in the UI. Examples of when this happens include:
|
||||
///
|
||||
/// • When the sent or read status of a message is updated.
|
||||
/// • When an attachment is uploaded or downloaded.
|
||||
@objc public final class MessageInvalidator : NSObject {
|
||||
private static var invalidatedMessages: Set<String> = []
|
||||
|
||||
@objc public static let shared = MessageInvalidator()
|
||||
|
||||
private override init() { }
|
||||
|
||||
@objc public static func invalidate(_ message: TSMessage, with transaction: YapDatabaseReadWriteTransaction) {
|
||||
guard let id = message.uniqueId, !isInvalidated(message) else { return }
|
||||
invalidatedMessages.insert(id)
|
||||
message.touch(with: transaction)
|
||||
}
|
||||
|
||||
@objc public static func isInvalidated(_ message: TSMessage) -> Bool {
|
||||
guard let id = message.uniqueId else { return false }
|
||||
return invalidatedMessages.contains(id)
|
||||
}
|
||||
|
||||
@objc public static func markAsUpdated(_ id: String) {
|
||||
invalidatedMessages.remove(id)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue