From 0f9b0936df28e6dfaaf57b9c223641f6a7580d3b Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 14 Sep 2018 10:29:18 -0500 Subject: [PATCH] Use cached group details when rendering blocklist --- Signal.xcodeproj/project.pbxproj | 4 ++ .../AppSettings/BlockListViewController.m | 18 +++-- Signal/src/views/AvatarTableViewCell.swift | 72 +++++++++++++++++++ SignalMessaging/utils/BlockListUIUtils.h | 7 ++ SignalMessaging/utils/OWSGroupAvatarBuilder.h | 3 +- SignalMessaging/utils/OWSGroupAvatarBuilder.m | 5 ++ .../src/Contacts/Threads/TSGroupThread.h | 2 + .../src/Contacts/Threads/TSGroupThread.m | 7 +- 8 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 Signal/src/views/AvatarTableViewCell.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index c890e4fbc..961e3e058 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -435,6 +435,7 @@ 4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */; }; 4C20B2B720CA0034001BAC90 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; }; 4C20B2B920CA10DE001BAC90 /* ConversationSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */; }; + 4C2F454F214C00E1004871FF /* AvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */; }; 4C3EF7FD2107DDEE0007EBF7 /* ParamParserTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */; }; 4C3EF802210918740007EBF7 /* SSKProtoEnvelopeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C3EF801210918740007EBF7 /* SSKProtoEnvelopeTest.swift */; }; 4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */; }; @@ -1125,6 +1126,7 @@ 4C11AA4F20FD59C700351FBD /* MessageStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageStatusView.swift; sourceTree = ""; }; 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = ""; }; 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearchViewController.swift; sourceTree = ""; }; + 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarTableViewCell.swift; sourceTree = ""; }; 4C3EF7FC2107DDEE0007EBF7 /* ParamParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParamParserTest.swift; sourceTree = ""; }; 4C3EF801210918740007EBF7 /* SSKProtoEnvelopeTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSKProtoEnvelopeTest.swift; sourceTree = ""; }; 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableTextField.swift; sourceTree = ""; }; @@ -2233,6 +2235,7 @@ isa = PBXGroup; children = ( 452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */, + 4C2F454E214C00E1004871FF /* AvatarTableViewCell.swift */, 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */, 451764291DE939FD00EDB8B9 /* ContactCell.swift */, 4523149F1F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift */, @@ -3327,6 +3330,7 @@ 451166C01FD86B98000739BA /* AccountManager.swift in Sources */, 34D2CCD220618B3000CB1A14 /* OWSBackupLazyRestoreJob.swift in Sources */, 3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */, + 4C2F454F214C00E1004871FF /* AvatarTableViewCell.swift in Sources */, 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */, 340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, diff --git a/Signal/src/ViewControllers/AppSettings/BlockListViewController.m b/Signal/src/ViewControllers/AppSettings/BlockListViewController.m index b4c5d0cb4..e5ea4cebf 100644 --- a/Signal/src/ViewControllers/AppSettings/BlockListViewController.m +++ b/Signal/src/ViewControllers/AppSettings/BlockListViewController.m @@ -9,6 +9,7 @@ #import "ContactsViewHelper.h" #import "OWSTableViewController.h" #import "PhoneNumber.h" +#import "Signal-Swift.h" #import "UIFont+OWS.h" #import "UIView+OWS.h" #import @@ -115,20 +116,25 @@ NS_ASSUME_NONNULL_BEGIN blockedGroupsSection.headerTitle = NSLocalizedString( @"BLOCK_LIST_BLOCKED_GROUPS_SECTION", @"Section header for groups that have been blocked"); for (NSData *groupId in blockedGroupIds) { - TSGroupThread *groupThread = [TSGroupThread getOrCreateThreadWithGroupId:groupId]; + TSGroupModel *_Nullable cachedGroup = [self.blockingManager cachedGroupDetailsWithGroupId:groupId]; + OWSAssert(cachedGroup); + UIImage *image = cachedGroup.groupImage ?: OWSGroupAvatarBuilder.defaultGroupImage; + NSString *groupName = cachedGroup.groupName ?: TSGroupThread.defaultGroupName; + [blockedGroupsSection addItem:[OWSTableItem itemWithCustomCellBlock:^{ - ContactTableViewCell *cell = [ContactTableViewCell new]; - [cell configureWithThread:groupThread - contactsManager:helper.contactsManager]; + OWSAvatarTableViewCell *cell = [OWSAvatarTableViewCell new]; + [cell configureWithImage:image + text:groupName + detailText:nil]; return cell; } customRowHeight:UITableViewAutomaticDimension actionBlock:^{ - [BlockListUIUtils showUnblockThreadActionSheet:groupThread + [BlockListUIUtils showUnblockGroupActionSheet:cachedGroup + displayName:groupName fromViewController:weakSelf blockingManager:helper.blockingManager - contactsManager:helper.contactsManager completionBlock:nil]; }]]; } diff --git a/Signal/src/views/AvatarTableViewCell.swift b/Signal/src/views/AvatarTableViewCell.swift new file mode 100644 index 000000000..e093a7501 --- /dev/null +++ b/Signal/src/views/AvatarTableViewCell.swift @@ -0,0 +1,72 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation + +@objc(OWSAvatarTableViewCell) +public class AvatarTableViewCell: UITableViewCell { + + private let columns: UIStackView + private let textRows: UIStackView + private let avatarView: AvatarImageView + + private let _textLabel: UILabel + override public var textLabel: UILabel? { + get { + return _textLabel + } + } + + private let _detailTextLabel: UILabel + override public var detailTextLabel: UILabel? { + get { + return _detailTextLabel + } + } + + @objc + public override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + self.avatarView = AvatarImageView() + avatarView.autoSetDimensions(to: CGSize(width: CGFloat(kContactCellAvatarSize), height: CGFloat(kContactCellAvatarSize))) + + self._textLabel = UILabel() + self._detailTextLabel = UILabel() + + self.textRows = UIStackView(arrangedSubviews: [_textLabel, _detailTextLabel]) + textRows.axis = .vertical + + self.columns = UIStackView(arrangedSubviews: [avatarView, textRows]) + columns.axis = .horizontal + columns.spacing = CGFloat(kContactCellAvatarTextMargin) + + super.init(style: style, reuseIdentifier: reuseIdentifier) + + self.contentView.addSubview(columns) + columns.autoPinEdgesToSuperviewMargins() + + OWSTableItem.configureCell(self) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc + public func configure(image: UIImage?, text: String?, detailText: String?) { + self.avatarView.image = image + self.textLabel?.text = text + self.detailTextLabel?.text = detailText + + OWSTableItem.configureCell(self) + } + + @objc + public override func prepareForReuse() { + super.prepareForReuse() + + self.avatarView.image = nil + self.textLabel?.text = nil + self.detailTextLabel?.text = nil + } +} diff --git a/SignalMessaging/utils/BlockListUIUtils.h b/SignalMessaging/utils/BlockListUIUtils.h index 23e46ebf6..77a7ec23a 100644 --- a/SignalMessaging/utils/BlockListUIUtils.h +++ b/SignalMessaging/utils/BlockListUIUtils.h @@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN @class OWSContactsManager; @class OWSMessageSender; @class SignalAccount; +@class TSGroupModel; @class TSThread; typedef void (^BlockActionCompletionBlock)(BOOL isBlocked); @@ -60,6 +61,12 @@ typedef void (^BlockActionCompletionBlock)(BOOL isBlocked); contactsManager:(OWSContactsManager *)contactsManager completionBlock:(nullable BlockActionCompletionBlock)completionBlock; ++ (void)showUnblockGroupActionSheet:(TSGroupModel *)groupModel + displayName:(NSString *)displayName + fromViewController:(UIViewController *)fromViewController + blockingManager:(OWSBlockingManager *)blockingManager + completionBlock:(nullable BlockActionCompletionBlock)completionBlock; + #pragma mark - UI Utils + (NSString *)formatDisplayNameForAlertTitle:(NSString *)displayName; diff --git a/SignalMessaging/utils/OWSGroupAvatarBuilder.h b/SignalMessaging/utils/OWSGroupAvatarBuilder.h index 6c3936e1e..36a9eeebb 100644 --- a/SignalMessaging/utils/OWSGroupAvatarBuilder.h +++ b/SignalMessaging/utils/OWSGroupAvatarBuilder.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSAvatarBuilder.h" @@ -11,6 +11,7 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSGroupAvatarBuilder : OWSAvatarBuilder - (instancetype)initWithThread:(TSGroupThread *)thread; ++ (UIImage *)defaultGroupImage; @end diff --git a/SignalMessaging/utils/OWSGroupAvatarBuilder.m b/SignalMessaging/utils/OWSGroupAvatarBuilder.m index fd5648f32..8a832a0d4 100644 --- a/SignalMessaging/utils/OWSGroupAvatarBuilder.m +++ b/SignalMessaging/utils/OWSGroupAvatarBuilder.m @@ -33,6 +33,11 @@ NS_ASSUME_NONNULL_BEGIN } - (UIImage *)buildDefaultImage +{ + return self.class.defaultGroupImage; +} + ++ (UIImage *)defaultGroupImage { static UIImage *defaultGroupImage; static dispatch_once_t onceToken; diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h index 60d49ba8f..5a937f509 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.h @@ -29,6 +29,8 @@ extern NSString *const TSGroupThread_NotificationKey_UniqueId; + (NSString *)threadIdFromGroupId:(NSData *)groupId; ++ (NSString *)defaultGroupName; + // all group threads containing recipient as a member + (NSArray *)groupThreadsWithRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index bd77dc373..80732c3dd 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -175,7 +175,12 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (NSString *)name { - return self.groupModel.groupName ? self.groupModel.groupName : NSLocalizedString(@"NEW_GROUP_DEFAULT_TITLE", @""); + return self.groupModel.groupName ?: self.class.defaultGroupName; +} + ++ (NSString *)defaultGroupName +{ + return NSLocalizedString(@"NEW_GROUP_DEFAULT_TITLE", @""); } - (void)leaveGroupWithSneakyTransaction