Start implementing device linking UI

This commit is contained in:
Niels Andriesse 2019-09-20 15:53:24 +10:00
parent da2d18f0fc
commit a604ba5646
8 changed files with 152 additions and 22 deletions

View File

@ -78,6 +78,7 @@ target 'Signal' do
pod 'FirebaseCore', '~> 6.0', :inhibit_warnings => true
pod 'Fabric', '~> 1.10', :inhibit_warnings => true
pod 'Crashlytics', '~> 3.13', :inhibit_warnings => true
pod 'NVActivityIndicatorView', '~> 4.7', :inhibit_warnings => true
target 'SignalTests' do
inherit! :search_paths

View File

@ -62,6 +62,9 @@ PODS:
- Mantle/extobjc (= 2.1.0)
- Mantle/extobjc (2.1.0)
- Mixpanel (3.4.7)
- NVActivityIndicatorView (4.7.0):
- NVActivityIndicatorView/Presenter (= 4.7.0)
- NVActivityIndicatorView/Presenter (4.7.0)
- PromiseKit (6.5.3):
- PromiseKit/CorePromise (= 6.5.3)
- PromiseKit/Foundation (= 6.5.3)
@ -220,6 +223,7 @@ DEPENDENCIES:
- IGIdenticon
- Mantle (from `https://github.com/signalapp/Mantle`, branch `signal-master`)
- Mixpanel (~> 3.4)
- NVActivityIndicatorView (~> 4.7)
- PromiseKit (= 6.5.3)
- PureLayout
- Reachability
@ -249,6 +253,7 @@ SPEC REPOS:
- IGIdenticon
- libPhoneNumber-iOS
- Mixpanel
- NVActivityIndicatorView
- PromiseKit
- PureLayout
- Reachability
@ -331,6 +336,7 @@ SPEC CHECKSUMS:
libPhoneNumber-iOS: e444379ac18bbfbdefad571da735b2cd7e096caa
Mantle: 2fa750afa478cd625a94230fbf1c13462f29395b
Mixpanel: 696e0a1c7f2685aa06bb23829b7a58ab7203d6c7
NVActivityIndicatorView: b19ddab2576f805cbe0fb2306cba3476e09a1dea
PromiseKit: c609029bdd801f792551a504c695c7d3098b42cd
PureLayout: f08c01b8dec00bb14a1fefa3de4c7d9c265df85e
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
@ -345,6 +351,6 @@ SPEC CHECKSUMS:
YapDatabase: b418a4baa6906e8028748938f9159807fd039af4
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
PODFILE CHECKSUM: 1240a47686acf0d2d7e61e6ec3a925fbded184fa
PODFILE CHECKSUM: ff66104e65cc960ed08a74b71c27f5caf59f4239
COCOAPODS: 1.5.3

View File

@ -568,6 +568,7 @@
B82584A02315024B001B41CB /* LokiRSSFeedPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */; };
B845B4D4230CD09100D759F0 /* LokiGroupChatPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */; };
B846365B22B7418B00AF1514 /* Identicon+ObjC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */; };
B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */; };
B891105C2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; };
B891105E2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; };
B891105F2320872800F15FCC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B891105B2320872800F15FCC /* GoogleService-Info.plist */; };
@ -1371,6 +1372,7 @@
B825849F2315024B001B41CB /* LokiRSSFeedPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiRSSFeedPoller.swift; sourceTree = "<group>"; };
B845B4D3230CD09000D759F0 /* LokiGroupChatPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LokiGroupChatPoller.swift; sourceTree = "<group>"; };
B846365A22B7418B00AF1514 /* Identicon+ObjC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Identicon+ObjC.swift"; sourceTree = "<group>"; };
B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinkingModal.swift; sourceTree = "<group>"; };
B891105B2320872800F15FCC /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
B89841E222B7579F00B1BDC6 /* NewConversationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationViewController.swift; sourceTree = "<group>"; };
B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = "<group>"; };
@ -2640,6 +2642,7 @@
B8258491230FA5DA001B41CB /* ScanQRCodeViewController.h */,
B8258492230FA5E9001B41CB /* ScanQRCodeViewController.m */,
B821F2F92272CEEE002C88C0 /* SeedViewController.swift */,
B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */,
);
path = Loki;
sourceTree = "<group>";
@ -3319,6 +3322,7 @@
"${BUILT_PRODUCTS_DIR}/IGIdenticon/IGIdenticon.framework",
"${BUILT_PRODUCTS_DIR}/Mantle/Mantle.framework",
"${BUILT_PRODUCTS_DIR}/Mixpanel/Mixpanel.framework",
"${BUILT_PRODUCTS_DIR}/NVActivityIndicatorView/NVActivityIndicatorView.framework",
"${BUILT_PRODUCTS_DIR}/PromiseKit/PromiseKit.framework",
"${BUILT_PRODUCTS_DIR}/PureLayout/PureLayout.framework",
"${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework",
@ -3349,6 +3353,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IGIdenticon.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mantle.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mixpanel.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NVActivityIndicatorView.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PromiseKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PureLayout.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework",
@ -3706,6 +3711,7 @@
450D19131F85236600970622 /* RemoteVideoView.m in Sources */,
34129B8621EF877A005457A8 /* LinkPreviewView.swift in Sources */,
34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */,
B885D5F4233491AB00EE0D8E /* DeviceLinkingModal.swift in Sources */,
45DF5DF21DDB843F00C936C7 /* CompareSafetyNumbersActivity.swift in Sources */,
451166C01FD86B98000739BA /* AccountManager.swift in Sources */,
3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */,

View File

@ -60,7 +60,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
static NSTimeInterval launchStartedAt;
@interface AppDelegate () <UNUserNotificationCenterDelegate, LKDeviceLinkingSessionDelegate>
@interface AppDelegate () <UNUserNotificationCenterDelegate>
@property (nonatomic) BOOL hasInitialRootViewController;
@property (nonatomic) BOOL areVersionMigrationsComplete;
@ -72,7 +72,6 @@ static NSTimeInterval launchStartedAt;
@property (nonatomic) LKGroupChatPoller *lokiPublicChatPoller;
@property (nonatomic) LKRSSFeedPoller *lokiNewsFeedPoller;
@property (nonatomic) LKRSSFeedPoller *lokiMessengerUpdatesFeedPoller;
@property (nonatomic) LKDeviceLinkingSession *lokiDeviceLinkingSession;
@end
@ -1639,21 +1638,4 @@ static NSTimeInterval launchStartedAt;
}
}
- (void)startListeningForLinkingRequests
{
[self.lokiDeviceLinkingSession stopListeningForLinkingRequests];
self.lokiDeviceLinkingSession = [[LKDeviceLinkingSession alloc] initWithDelegate:self];
[self.lokiDeviceLinkingSession startListeningForLinkingRequests];
}
- (void)requestUserAuthorizationFor:(LKDeviceLink *)deviceLink
{
}
- (void)handleDeviceLinkingSessionTimeout
{
}
@end

View File

@ -0,0 +1,131 @@
import NVActivityIndicatorView
@objc(LKDeviceLinkingModal)
final class DeviceLinkingModal : UIViewController, LokiDeviceLinkingSessionDelegate {
private lazy var deviceLinkingSession: LokiDeviceLinkingSession = {
return LokiDeviceLinkingSession(delegate: self)
}()
// MARK: Components
private lazy var contentView: UIView = {
let result = UIView()
result.backgroundColor = .lokiDarkGray()
result.layer.cornerRadius = 4
result.layer.masksToBounds = false
result.layer.shadowColor = UIColor.black.cgColor
result.layer.shadowRadius = 8
result.layer.shadowOpacity = 0.64
return result
}()
private lazy var spinner = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: .white, padding: nil)
private lazy var titleLabel: UILabel = {
let result = UILabel()
result.textColor = Theme.primaryColor
result.font = UIFont.ows_dynamicTypeHeadlineClamped
result.text = NSLocalizedString("Waiting for Device", comment: "")
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
result.textAlignment = .center
return result
}()
private lazy var subtitleLabel: UILabel = {
let result = UILabel()
result.textColor = Theme.primaryColor
result.font = UIFont.ows_dynamicTypeCaption1Clamped
result.text = NSLocalizedString("Click the \"Link Device\" button on your other device to start the linking process", comment: "")
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
result.textAlignment = .center
return result
}()
private lazy var cancelButton: OWSFlatButton = {
let result = OWSFlatButton.button(title: NSLocalizedString("Cancel", comment: ""), font: .ows_dynamicTypeBodyClamped, titleColor: .white, backgroundColor: .clear, target: self, selector: #selector(cancel))
result.setBackgroundColors(upColor: .clear, downColor: .clear)
return result
}()
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpViewHierarchy()
deviceLinkingSession.startListeningForLinkingRequests()
}
private func setUpViewHierarchy() {
view.backgroundColor = .clear
// Content view
view.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 32),
view.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 32),
contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
// Spinner
contentView.addSubview(spinner)
spinner.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
spinner.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
spinner.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 32),
spinner.heightAnchor.constraint(equalToConstant: 64),
spinner.widthAnchor.constraint(equalToConstant: 64)
])
spinner.startAnimating()
// Title label
contentView.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
titleLabel.topAnchor.constraint(equalTo: spinner.bottomAnchor, constant: 32),
contentView.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 16)
])
// Subtitle label
contentView.addSubview(subtitleLabel)
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
subtitleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 16),
contentView.trailingAnchor.constraint(equalTo: subtitleLabel.trailingAnchor, constant: 16)
])
// Cancel button
contentView.addSubview(cancelButton)
cancelButton.translatesAutoresizingMaskIntoConstraints = false
let cancelButtonHeight = cancelButton.button.titleLabel!.font.pointSize * 48 / 17
NSLayoutConstraint.activate([
cancelButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
cancelButton.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 16),
contentView.trailingAnchor.constraint(equalTo: cancelButton.trailingAnchor, constant: 16),
contentView.bottomAnchor.constraint(equalTo: cancelButton.bottomAnchor, constant: 16),
cancelButton.heightAnchor.constraint(equalToConstant: cancelButtonHeight)
])
}
// MARK: Device Linking
func requestUserAuthorization(for deviceLink: LokiDeviceLink) {
}
func handleDeviceLinkingSessionTimeout() {
}
// MARK: Interaction
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in: view)
if contentView.frame.contains(location) {
super.touchesBegan(touches, with: event)
} else {
dismiss(animated: true, completion: nil)
}
}
@objc private func cancel() {
dismiss(animated: true, completion: nil)
}
}

View File

@ -514,7 +514,9 @@
- (void)linkDevice
{
LKDeviceLinkingModal *deviceLinkingModal = [LKDeviceLinkingModal new];
deviceLinkingModal.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:deviceLinkingModal animated:YES completion:nil];
}
- (void)showSeed

View File

@ -2622,3 +2622,5 @@
"Loki Messenger is currently in beta. For development purposes the beta version collects basic usage statistics and crash logs. In addition, the beta version doesn't provide full privacy and shouldn't be used to transmit sensitive information." = "Loki Messenger is currently in beta. For development purposes the beta version collects basic usage statistics and crash logs. In addition, the beta version doesn't provide full privacy and shouldn't be used to transmit sensitive information.";
"Copy Public Key" = "Copy Public Key";
"Link Device" = "Link Device";
"Waiting for Device" = "Waiting for Device";
"Click the \"Link Device\" button on your other device to start the linking process" = "Click the \"Link Device\" button on your other device to start the linking process";

View File

@ -1,7 +1,7 @@
import PromiseKit
@objc (LKDeviceLinkingSession)
final class LokiDeviceLinkingSession : NSObject {
public final class LokiDeviceLinkingSession : NSObject {
private let delegate: LokiDeviceLinkingSessionDelegate
private var timer: Timer?
@objc public var isListeningForLinkingRequests = false