Implement incoming friend request UI

This commit is contained in:
Niels Andriesse 2019-05-13 15:21:16 +10:00
parent 0a653e928b
commit 3dda1f17e1
11 changed files with 127 additions and 7 deletions

View File

@ -555,6 +555,8 @@
B6B226971BE4B7D200860F4D /* ContactsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6B226961BE4B7D200860F4D /* ContactsUI.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
B6F509971AA53F760068F56A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; };
B6FE7EB71ADD62FA00A6D22F /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */; };
B8162F0322891AD600D46544 /* FriendRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8162F0222891AD600D46544 /* FriendRequestView.swift */; };
B8162F0522892C5F00D46544 /* FriendRequestViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */; };
B821F2F82272CED3002C88C0 /* OnboardingAccountDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B821F2F72272CED3002C88C0 /* OnboardingAccountDetailsViewController.swift */; };
B821F2FA2272CEEE002C88C0 /* OnboardingKeyPairViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B821F2F92272CEEE002C88C0 /* OnboardingKeyPairViewController.swift */; };
B843951A228510FB000563FE /* Poller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8439519228510FB000563FE /* Poller.swift */; };
@ -1340,6 +1342,8 @@
B6BC3D0C1AA544B100C2907F /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = translations/da.lproj/Localizable.strings; sourceTree = "<group>"; };
B6F509961AA53F760068F56A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = translations/en.lproj/Localizable.strings; sourceTree = "<group>"; };
B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = System/Library/Frameworks/PushKit.framework; sourceTree = SDKROOT; };
B8162F0222891AD600D46544 /* FriendRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendRequestView.swift; sourceTree = "<group>"; };
B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendRequestViewDelegate.swift; sourceTree = "<group>"; };
B821F2F72272CED3002C88C0 /* OnboardingAccountDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingAccountDetailsViewController.swift; sourceTree = "<group>"; };
B821F2F92272CEEE002C88C0 /* OnboardingKeyPairViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingKeyPairViewController.swift; sourceTree = "<group>"; };
B8439519228510FB000563FE /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Poller.swift; path = Signal/src/Loki/Poller.swift; sourceTree = SOURCE_ROOT; };
@ -1526,13 +1530,11 @@
children = (
3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */,
349ED98F221B0194008045B0 /* Onboarding2FAViewController.swift */,
B821F2F72272CED3002C88C0 /* OnboardingAccountDetailsViewController.swift */,
3448E1612213585C004B052E /* OnboardingBaseViewController.swift */,
3448E1652215B313004B052E /* OnboardingCaptchaViewController.swift */,
3448E15D221333F5004B052E /* OnboardingController.swift */,
3448E15B22133274004B052E /* OnboardingPermissionsViewController.swift */,
34A4C61F22175C5C0042EF2E /* OnboardingProfileViewController.swift */,
B821F2F92272CEEE002C88C0 /* OnboardingKeyPairViewController.swift */,
3448E15F22134C88004B052E /* OnboardingSplashViewController.swift */,
34A4C61D221613D00042EF2E /* OnboardingVerificationViewController.swift */,
346E9D5321B040B600562252 /* RegistrationController.swift */,
@ -2599,6 +2601,10 @@
B8439518228510E9000563FE /* Loki */ = {
isa = PBXGroup;
children = (
B8162F0222891AD600D46544 /* FriendRequestView.swift */,
B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */,
B821F2F72272CED3002C88C0 /* OnboardingAccountDetailsViewController.swift */,
B821F2F92272CEEE002C88C0 /* OnboardingKeyPairViewController.swift */,
B8439519228510FB000563FE /* Poller.swift */,
);
path = Loki;
@ -3675,10 +3681,12 @@
457C87B82032645C008D52D6 /* DebugUINotifications.swift in Sources */,
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */,
4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */,
B8162F0522892C5F00D46544 /* FriendRequestViewDelegate.swift in Sources */,
B821F2FA2272CEEE002C88C0 /* OnboardingKeyPairViewController.swift in Sources */,
4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */,
3448E16022134C89004B052E /* OnboardingSplashViewController.swift in Sources */,
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */,
B8162F0322891AD600D46544 /* FriendRequestView.swift in Sources */,
458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */,
34B6A905218B4C91007C4606 /* TypingIndicatorInteraction.swift in Sources */,
4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */,

View File

@ -0,0 +1,63 @@
@objc final class FriendRequestView : UIView {
@objc var message: TSIncomingMessage! { didSet { handleMessageChanged() } }
@objc weak var delegate: FriendRequestViewDelegate?
// MARK: Components
private lazy var label: UILabel = {
let result = UILabel()
result.textColor = Theme.secondaryColor
result.font = UIFont.ows_dynamicTypeSubheadlineClamped
result.numberOfLines = 0
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
return result
}()
// MARK: Initialization
required init?(coder: NSCoder) {
super.init(coder: coder)
initialize()
}
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
private func initialize() {
let mainStackView = UIStackView()
mainStackView.axis = .vertical
mainStackView.distribution = .fill
mainStackView.addArrangedSubview(label)
let buttonStackView = UIStackView()
buttonStackView.axis = .horizontal
buttonStackView.distribution = .fillEqually
mainStackView.addArrangedSubview(buttonStackView)
let buttonFont = UIFont.ows_dynamicTypeBodyClamped.ows_mediumWeight()
let buttonHeight = buttonFont.pointSize * 48 / 17
let acceptButton = OWSFlatButton.button(title: NSLocalizedString("Accept", comment: ""), font: buttonFont, titleColor: .ows_materialBlue, backgroundColor: .clear, target: self, selector: #selector(accept))
acceptButton.autoSetDimension(.height, toSize: buttonHeight)
buttonStackView.addArrangedSubview(acceptButton)
let declineButton = OWSFlatButton.button(title: NSLocalizedString("Decline", comment: ""), font: buttonFont, titleColor: .ows_destructiveRed, backgroundColor: .clear, target: self, selector: #selector(decline))
declineButton.autoSetDimension(.height, toSize: buttonHeight)
buttonStackView.addArrangedSubview(declineButton)
addSubview(mainStackView)
mainStackView.autoPin(toEdgesOf: self)
}
// MARK: Updating
private func handleMessageChanged() {
assert(message != nil)
label.text = String(format: NSLocalizedString("%@ sent you a friend request", comment: ""), message.authorId)
}
// MARK: Interaction
@objc private func accept() {
delegate?.acceptFriendRequest(message)
}
@objc private func decline() {
delegate?.declineFriendRequest(message)
}
}

View File

@ -0,0 +1,5 @@
@objc protocol FriendRequestViewDelegate {
@objc func acceptFriendRequest(_ friendRequest: TSIncomingMessage)
@objc func declineFriendRequest(_ friendRequest: TSIncomingMessage)
}

View File

@ -65,7 +65,7 @@ final class OnboardingAccountDetailsViewController : OnboardingBaseViewControlle
topSpacer.autoMatch(.height, to: .height, of: bottomSpacer)
}
public override func viewDidAppear(_ animated: Bool) {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
userNameTextField.becomeFirstResponder()
}

View File

@ -91,7 +91,7 @@ final class OnboardingKeyPairViewController : OnboardingBaseViewController {
self.userName = userName
}
override public func viewDidLoad() {
override func viewDidLoad() {
super.loadView()
setUpViewHierarchy()
handleModeChanged() // Perform initial update

View File

@ -1,6 +1,6 @@
import PromiseKit
@objc public final class Poller : NSObject {
@objc final class Poller : NSObject {
private var isStarted = false
private var currentJob: Promise<Void>?
@ -8,12 +8,12 @@ import PromiseKit
private static let interval: TimeInterval = 30
// MARK: Initialization
@objc public static let shared = Poller()
@objc static let shared = Poller()
private override init() { }
// MARK: General
@objc public func startIfNeeded() {
@objc func startIfNeeded() {
guard !isStarted else { return }
Timer.scheduledTimer(timeInterval: Poller.interval, target: self, selector: #selector(poll), userInfo: nil, repeats: true)
isStarted = true

View File

@ -5,12 +5,14 @@
#import "ConversationViewCell.h"
@class OWSMessageBubbleView;
@protocol FriendRequestViewDelegate;
NS_ASSUME_NONNULL_BEGIN
@interface OWSMessageCell : ConversationViewCell
@property (nonatomic, readonly) OWSMessageBubbleView *messageBubbleView;
@property (nonatomic, nullable, weak) id<FriendRequestViewDelegate> friendRequestViewDelegate;
+ (NSString *)cellReuseIdentifier;

View File

@ -19,6 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) OWSMessageHeaderView *headerView;
@property (nonatomic) OWSMessageBubbleView *messageBubbleView;
@property (nonatomic) AvatarImageView *avatarView;
@property (nonatomic, nullable) FriendRequestView *friendRequestView;
@property (nonatomic, nullable) UIImageView *sendFailureBadgeView;
@property (nonatomic, nullable) NSMutableArray<NSLayoutConstraint *> *viewConstraints;
@ -164,6 +165,21 @@ NS_ASSUME_NONNULL_BEGIN
withInset:self.conversationStyle.gutterTrailing
relation:NSLayoutRelationGreaterThanOrEqual],
]];
if ([self.viewItem.interaction isKindOfClass:TSIncomingMessage.class]) {
TSIncomingMessage *message = (TSIncomingMessage *)self.message;
if (YES) { // TODO: message.isFriendRequest
self.friendRequestView = [FriendRequestView new];
self.friendRequestView.message = message;
self.friendRequestView.delegate = self.friendRequestViewDelegate;
[self.contentView addSubview:self.friendRequestView];
[self.viewConstraints addObjectsFromArray:@[
[self.friendRequestView autoPinEdgeToSuperviewEdge:ALEdgeLeading withInset:self.conversationStyle.gutterLeading],
[self.friendRequestView autoPinEdgeToSuperviewEdge:ALEdgeTrailing withInset:self.conversationStyle.gutterTrailing],
[self.friendRequestView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.messageBubbleView withOffset:12.f]
]];
}
}
} else {
if (self.shouldHaveSendFailureBadge) {
self.sendFailureBadgeView = [UIImageView new];
@ -339,6 +355,10 @@ NS_ASSUME_NONNULL_BEGIN
if (self.shouldHaveSendFailureBadge) {
cellSize.width += self.sendFailureBadgeSize + self.sendFailureBadgeSpacing;
}
if (self.friendRequestView != nil) {
cellSize.height += 118.f; // TODO: Measure dynamically
}
cellSize = CGSizeCeil(cellSize);
@ -359,6 +379,9 @@ NS_ASSUME_NONNULL_BEGIN
[self.headerView removeFromSuperview];
[self.friendRequestView removeFromSuperview];
self.friendRequestView = nil;
self.avatarView.image = nil;
[self.avatarView removeFromSuperview];

View File

@ -123,6 +123,7 @@ typedef enum : NSUInteger {
ConversationViewCellDelegate,
ConversationInputTextViewDelegate,
ConversationSearchControllerDelegate,
FriendRequestViewDelegate,
LongTextViewDelegate,
MessageActionsDelegate,
MessageDetailViewDelegate,
@ -4282,6 +4283,18 @@ typedef enum : NSUInteger {
animated:YES];
}
#pragma mark - FriendRequestViewDelegate
- (void)acceptFriendRequest:(TSIncomingMessage *)friendRequest
{
[ThreadUtil enqueueFriendRequestAcceptMessageInThread:self.thread];
}
- (void)declineFriendRequest:(TSIncomingMessage *)friendRequest
{
OWSLogDebug(@"decline friend request button pressed"); // TODO: Implement
}
#pragma mark - ConversationViewLayoutDelegate
- (NSArray<id<ConversationViewLayoutItem>> *)layoutItems
@ -4567,6 +4580,7 @@ typedef enum : NSUInteger {
if ([cell isKindOfClass:[OWSMessageCell class]]) {
OWSMessageCell *messageCell = (OWSMessageCell *)cell;
messageCell.messageBubbleView.delegate = self;
messageCell.friendRequestViewDelegate = self;
}
cell.conversationStyle = self.conversationStyle;

View File

@ -2571,3 +2571,6 @@
"Calculating proof of work" = "Calculating proof of work";
"Failed to calculate proof of work." = "Failed to calculate proof of work.";
"Share Public Key" = "Share Public Key";
"%@ sent you a friend request" = "%@ sent you a friend request";
"Accept" = "Accept";
"Decline" = "Decline";

View File

@ -44,6 +44,8 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Durable Message Enqueue
+ (TSOutgoingMessage *)enqueueFriendRequestAcceptMessageInThread:(TSThread *)thread;
+ (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText
inThread:(TSThread *)thread
quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel