Refactor friend request view & add documentation
This commit is contained in:
parent
4c33fa257a
commit
1a8175472a
|
@ -1,8 +1,12 @@
|
|||
|
||||
@objc final class FriendRequestView : UIView {
|
||||
@objc var message: TSMessage! { didSet { handleMessageChanged() } }
|
||||
private let message: TSMessage
|
||||
@objc weak var delegate: FriendRequestViewDelegate?
|
||||
private let kind: Kind
|
||||
|
||||
private var kind: Kind {
|
||||
let isIncoming = message.interactionType() == .incomingMessage
|
||||
return isIncoming ? .incoming : .outgoing
|
||||
}
|
||||
|
||||
// MARK: Types
|
||||
enum Kind : String { case incoming, outgoing }
|
||||
|
@ -29,26 +33,17 @@
|
|||
private lazy var buttonHeight = buttonFont.pointSize * 48 / 17
|
||||
|
||||
// MARK: Initialization
|
||||
init(kind: Kind) {
|
||||
self.kind = kind
|
||||
@objc init(message: TSMessage) {
|
||||
self.message = message
|
||||
super.init(frame: CGRect.zero)
|
||||
initialize()
|
||||
}
|
||||
|
||||
@objc convenience init?(rawKind: String) {
|
||||
guard let kind = Kind(rawValue: rawKind) else { return nil }
|
||||
self.init(kind: kind)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("Using FriendRequestView.init(coder:) isn't allowed. Use FriendRequestView.init(kind:) instead.")
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
fatalError("Using FriendRequestView.init(frame:) isn't allowed. Use FriendRequestView.init(kind:) instead.")
|
||||
}
|
||||
required init?(coder: NSCoder) { fatalError("Using FriendRequestView.init(coder:) isn't allowed. Use FriendRequestView.init(message:) instead.") }
|
||||
override init(frame: CGRect) { fatalError("Using FriendRequestView.init(frame:) isn't allowed. Use FriendRequestView.init(message:) instead.") }
|
||||
|
||||
private func initialize() {
|
||||
// Set up UI
|
||||
let mainStackView = UIStackView()
|
||||
mainStackView.axis = .vertical
|
||||
mainStackView.distribution = .fill
|
||||
|
@ -66,6 +61,8 @@
|
|||
}
|
||||
addSubview(mainStackView)
|
||||
mainStackView.autoPin(toEdgesOf: self)
|
||||
updateUI()
|
||||
// Observe friend request status changes
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(handleFriendRequestStatusChangedNotification), name: .messageFriendRequestStatusChanged, object: nil)
|
||||
}
|
||||
|
||||
|
@ -75,17 +72,17 @@
|
|||
|
||||
// MARK: Updating
|
||||
@objc private func handleFriendRequestStatusChangedNotification(_ notification: Notification) {
|
||||
guard let messageID = notification.object as? String, messageID == message?.uniqueId else { return }
|
||||
let messageID = notification.object as! String
|
||||
guard messageID == message.uniqueId else { return }
|
||||
message.reload()
|
||||
handleMessageChanged()
|
||||
updateUI()
|
||||
}
|
||||
|
||||
@objc private func handleMessageChanged() {
|
||||
precondition(message != nil)
|
||||
private func updateUI() {
|
||||
switch kind {
|
||||
case .incoming:
|
||||
guard let message = message as? TSIncomingMessage else { preconditionFailure() }
|
||||
buttonStackView.isHidden = !(message.friendRequestStatus == .pending)
|
||||
buttonStackView.isHidden = message.friendRequestStatus != .pending
|
||||
let format: String = {
|
||||
switch (message.friendRequestStatus) {
|
||||
case .accepted: return NSLocalizedString("You've accepted %@'s friend request", comment: "")
|
||||
|
@ -125,25 +122,11 @@
|
|||
@objc static func calculateHeight(message: TSMessage, conversationStyle: ConversationStyle) -> CGFloat {
|
||||
let width = conversationStyle.contentWidth
|
||||
let topSpacing: CGFloat = 12
|
||||
let kind: Kind = {
|
||||
switch (message) {
|
||||
case is TSIncomingMessage: return .incoming
|
||||
case is TSOutgoingMessage: return .outgoing
|
||||
default: preconditionFailure()
|
||||
}
|
||||
}()
|
||||
let dummyFriendRequestView = FriendRequestView(kind: kind)
|
||||
dummyFriendRequestView.message = message
|
||||
let messageHeight = dummyFriendRequestView.label.sizeThatFits(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)).height
|
||||
let totalHeight: CGFloat = {
|
||||
switch kind {
|
||||
case .incoming:
|
||||
let buttonHeight = dummyFriendRequestView.buttonStackView.isHidden ? 0 : dummyFriendRequestView.buttonHeight
|
||||
return topSpacing + messageHeight + buttonHeight
|
||||
case .outgoing:
|
||||
return topSpacing + messageHeight
|
||||
}
|
||||
}()
|
||||
let dummyFriendRequestView = FriendRequestView(message: message)
|
||||
let labelHeight = dummyFriendRequestView.label.sizeThatFits(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)).height
|
||||
let hasButtonStackView = dummyFriendRequestView.buttonStackView.superview != nil && !dummyFriendRequestView.buttonStackView.isHidden
|
||||
let buttonHeight = hasButtonStackView ? dummyFriendRequestView.buttonHeight : 0
|
||||
let totalHeight = topSpacing + labelHeight + buttonHeight
|
||||
return totalHeight.rounded(.up)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
|
||||
@objc protocol FriendRequestViewDelegate {
|
||||
/// Implementations of this method should update the thread's friend request status
|
||||
/// and send a friend request accepted message.
|
||||
@objc func acceptFriendRequest(_ friendRequest: TSIncomingMessage)
|
||||
/// Implementations of this method should update the thread's friend request status
|
||||
/// and remove the prekeys associated with the contact.
|
||||
@objc func declineFriendRequest(_ friendRequest: TSIncomingMessage)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#import "ConversationViewCell.h"
|
||||
|
||||
@class OWSMessageBubbleView;
|
||||
@class FriendRequestView;
|
||||
@protocol FriendRequestViewDelegate;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
@ -13,7 +12,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface OWSMessageCell : ConversationViewCell
|
||||
|
||||
@property (nonatomic, readonly) OWSMessageBubbleView *messageBubbleView;
|
||||
@property (nonatomic, readonly, nullable) FriendRequestView *friendRequestView;
|
||||
@property (nonatomic, nullable, weak) id<FriendRequestViewDelegate> friendRequestViewDelegate;
|
||||
|
||||
+ (NSString *)cellReuseIdentifier;
|
||||
|
|
|
@ -207,9 +207,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}
|
||||
|
||||
if (self.message.isFriendRequest) {
|
||||
NSString *rawKind = self.message.interactionType == OWSInteractionType_IncomingMessage ? @"incoming" : @"outgoing";
|
||||
self.friendRequestView = [[FriendRequestView alloc] initWithRawKind:rawKind];
|
||||
self.friendRequestView.message = self.message;
|
||||
self.friendRequestView = [[FriendRequestView alloc] initWithMessage:self.message];
|
||||
self.friendRequestView.delegate = self.friendRequestViewDelegate;
|
||||
[self.contentView addSubview:self.friendRequestView];
|
||||
[self.messageBubbleViewBottomConstraint setActive:NO];
|
||||
|
|
|
@ -4314,18 +4314,18 @@ typedef enum : NSUInteger {
|
|||
|
||||
- (void)acceptFriendRequest:(TSIncomingMessage *)friendRequest
|
||||
{
|
||||
// Update the thread's friend request state
|
||||
// Update the thread's friend request status
|
||||
[self.thread saveFriendRequestStatus:TSThreadFriendRequestStatusFriends withTransaction:nil];
|
||||
// Send friend request accepted message
|
||||
// Send a friend request accepted message
|
||||
[ThreadUtil enqueueAcceptFriendRequestMessageInThread:self.thread];
|
||||
}
|
||||
|
||||
- (void)declineFriendRequest:(TSIncomingMessage *)friendRequest
|
||||
{
|
||||
// Reset friend request status
|
||||
// Reset the thread's friend request status
|
||||
[self.thread saveFriendRequestStatus:TSThreadFriendRequestStatusNone withTransaction:nil];
|
||||
// Delete prekeys
|
||||
NSString *contactID = self.thread.recipientIdentifiers.firstObject;
|
||||
NSString *contactID = friendRequest.authorId;
|
||||
OWSPrimaryStorage *primaryStorage = SSKEnvironment.shared.primaryStorage;
|
||||
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[primaryStorage removePreKeyBundleForContact:contactID transaction:transaction];
|
||||
|
|
|
@ -31,17 +31,17 @@ extern ConversationColorName const kConversationColorName_Default;
|
|||
|
||||
// Loki: Friend request status
|
||||
typedef NS_ENUM(NSInteger, TSThreadFriendRequestStatus) {
|
||||
/// New conversation, no messages sent or received
|
||||
/// New conversation, no messages sent or received.
|
||||
TSThreadFriendRequestStatusNone,
|
||||
/// This state is used to lock the input early while sending
|
||||
/// This state is used to lock the input early while sending.
|
||||
TSThreadFriendRequestStatusRequestSending,
|
||||
/// Friend request sent, awaiting response
|
||||
/// Friend request sent, awaiting response.
|
||||
TSThreadFriendRequestStatusRequestSent,
|
||||
/// Friend request received, awaiting user input
|
||||
/// Friend request received, awaiting user input.
|
||||
TSThreadFriendRequestStatusRequestReceived,
|
||||
/// We are friends with the user of this thread
|
||||
/// We are friends with the other user in this thread.
|
||||
TSThreadFriendRequestStatusFriends,
|
||||
/// Friend request sent but it timed out (user didn't accept within x time)
|
||||
/// Friend request sent but it timed out (i.e. the other user didn't accept within the allocated time).
|
||||
TSThreadFriendRequestStatusRequestExpired
|
||||
};
|
||||
|
||||
|
|
|
@ -726,16 +726,14 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
NSMutableArray<NSString *> *idsToRemove = [NSMutableArray new];
|
||||
__block TSMessage *_Nullable messageToKeep = nil; // We want to keep this interaction and not remove it
|
||||
|
||||
[self enumerateInteractionsWithTransaction:transaction usingBlock:^(TSInteraction * _Nonnull interaction, YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
if (interaction.interactionType != interactionType) {
|
||||
return;
|
||||
}
|
||||
[self enumerateInteractionsWithTransaction:transaction usingBlock:^(TSInteraction *interaction, YapDatabaseReadTransaction *transaction) {
|
||||
if (interaction.interactionType != interactionType) { return; }
|
||||
|
||||
BOOL removeMessage = false;
|
||||
TSMessage *message = (TSMessage *)interaction;
|
||||
|
||||
// We want to keep the most recent message
|
||||
if (!messageToKeep || messageToKeep.timestamp < message.timestamp) {
|
||||
if (messageToKeep == nil || messageToKeep.timestamp < message.timestamp) {
|
||||
messageToKeep = message;
|
||||
}
|
||||
|
||||
|
@ -755,11 +753,9 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa
|
|||
|
||||
for (NSString *interactionId in idsToRemove) {
|
||||
// Don't delete the recent message
|
||||
if (messageToKeep && interactionId == messageToKeep.uniqueId) {
|
||||
continue;
|
||||
}
|
||||
if (messageToKeep != nil && interactionId == messageToKeep.uniqueId) { continue; }
|
||||
|
||||
// We need to fetch each interaction, since [TSInteraction removeWithTransaction:] does important work.
|
||||
// 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.");
|
||||
|
|
Loading…
Reference in New Issue