diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7f8ffe8a8..5b8ec972e 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -560,6 +560,9 @@ 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 */; }; + B80C6B572384A56D00FDBC8B /* DeviceLinksVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */; }; + B80C6B592384C4E700FDBC8B /* DeviceNameModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */; }; + B80C6B5B2384C7F900FDBC8B /* DeviceNameModalDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */; }; B8162F0322891AD600D46544 /* FriendRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8162F0222891AD600D46544 /* FriendRequestView.swift */; }; B8162F0522892C5F00D46544 /* FriendRequestViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */; }; B821F2F82272CED3002C88C0 /* DisplayNameVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B821F2F72272CED3002C88C0 /* DisplayNameVC.swift */; }; @@ -1371,6 +1374,9 @@ B6BC3D0C1AA544B100C2907F /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = translations/da.lproj/Localizable.strings; sourceTree = ""; }; B6F509961AA53F760068F56A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = translations/en.lproj/Localizable.strings; sourceTree = ""; }; B6FE7EB61ADD62FA00A6D22F /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = System/Library/Frameworks/PushKit.framework; sourceTree = SDKROOT; }; + B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceLinksVC.swift; sourceTree = ""; }; + B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceNameModal.swift; sourceTree = ""; }; + B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceNameModalDelegate.swift; sourceTree = ""; }; B8162F0222891AD600D46544 /* FriendRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendRequestView.swift; sourceTree = ""; }; B8162F0422892C5F00D46544 /* FriendRequestViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendRequestViewDelegate.swift; sourceTree = ""; }; B821F2F72272CED3002C88C0 /* DisplayNameVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayNameVC.swift; sourceTree = ""; }; @@ -2670,6 +2676,9 @@ children = ( B885D5F3233491AB00EE0D8E /* DeviceLinkingModal.swift */, B894D0702339D6F300B4D94D /* DeviceLinkingModalDelegate.swift */, + B80C6B562384A56D00FDBC8B /* DeviceLinksVC.swift */, + B80C6B582384C4E700FDBC8B /* DeviceNameModal.swift */, + B80C6B5A2384C7F900FDBC8B /* DeviceNameModalDelegate.swift */, B894D0742339EDCF00B4D94D /* NukeDataModal.swift */, B86BD08023399883000F5AE3 /* QRCodeModal.swift */, B86BD08523399CEF000F5AE3 /* SeedModal.swift */, @@ -3730,6 +3739,7 @@ 34D1F0501F7D45A60066283D /* GifPickerCell.swift in Sources */, 3496957421A301A100DCFE74 /* OWSBackupAPI.swift in Sources */, 34D99C931F2937CC00D284D6 /* OWSAnalytics.swift in Sources */, + B80C6B5B2384C7F900FDBC8B /* DeviceNameModalDelegate.swift in Sources */, 340FC8B8204DAC8D007AEB0F /* AddToGroupViewController.m in Sources */, 341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */, B893063F2383961A005EAA8E /* ScanQRCodeWrapperVC.swift in Sources */, @@ -3770,6 +3780,7 @@ 346E9D5421B040B700562252 /* RegistrationController.swift in Sources */, 340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, + B80C6B592384C4E700FDBC8B /* DeviceNameModal.swift in Sources */, 4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */, 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, @@ -3780,6 +3791,7 @@ 3403B95D20EA9527001A1F44 /* OWSContactShareButtonsView.m in Sources */, 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */, 34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */, + B80C6B572384A56D00FDBC8B /* DeviceLinksVC.swift in Sources */, 34A8B3512190A40E00218A25 /* MediaAlbumCellView.swift in Sources */, 34D1F0AE1F867BFC0066283D /* OWSMessageCell.m in Sources */, 4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */, diff --git a/Signal/src/Loki/Settings/DeviceLinkingModal.swift b/Signal/src/Loki/Settings/DeviceLinkingModal.swift index 8d9947410..d15a26871 100644 --- a/Signal/src/Loki/Settings/DeviceLinkingModal.swift +++ b/Signal/src/Loki/Settings/DeviceLinkingModal.swift @@ -145,7 +145,9 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { dismiss(animated: true, completion: nil) let master = DeviceLink.Device(hexEncodedPublicKey: deviceLink.master.hexEncodedPublicKey, signature: linkingAuthorizationMessage.masterSignature) let signedDeviceLink = DeviceLink(between: master, and: deviceLink.slave) - LokiStorageAPI.addDeviceLink(signedDeviceLink).catch { error in + LokiStorageAPI.addDeviceLink(signedDeviceLink).done { [weak self] in + self?.delegate?.handleDeviceLinkAuthorized(signedDeviceLink) + }.catch { error in print("[Loki] Failed to add device link due to error: \(error).") } Timer.scheduledTimer(withTimeInterval: 8, repeats: false) { _ in diff --git a/Signal/src/Loki/Settings/DeviceLinksVC.swift b/Signal/src/Loki/Settings/DeviceLinksVC.swift new file mode 100644 index 000000000..56c826d4b --- /dev/null +++ b/Signal/src/Loki/Settings/DeviceLinksVC.swift @@ -0,0 +1,192 @@ + +// MARK: - Device Links View Controller + +@objc(LKDeviceLinksVC) +final class DeviceLinksVC : UIViewController, UITableViewDataSource, UITableViewDelegate, DeviceLinkingModalDelegate, DeviceNameModalDelegate { + private var deviceLinks: [DeviceLink] = [] { didSet { updateUI() } } + + // MARK: Components + private lazy var tableView: UITableView = { + let result = UITableView() + result.dataSource = self + result.delegate = self + result.register(Cell.self, forCellReuseIdentifier: "Cell") + result.separatorStyle = .none + result.backgroundColor = .clear + return result + }() + + private lazy var callToActionView : UIStackView = { + let explanationLabel = UILabel() + explanationLabel.textColor = Theme.primaryColor + explanationLabel.font = UIFont.ows_dynamicTypeSubheadlineClamped + explanationLabel.numberOfLines = 0 + explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.textAlignment = .center + explanationLabel.text = NSLocalizedString("You don't have any linked devices yet", comment: "") + let linkNewDeviceButtonFont = UIFont.ows_dynamicTypeBodyClamped.ows_mediumWeight() + let linkNewDeviceButtonHeight = linkNewDeviceButtonFont.pointSize * 48 / 17 + let linkNewDeviceButton = OWSFlatButton.button(title: NSLocalizedString("Link a Device", comment: ""), font: linkNewDeviceButtonFont, titleColor: .lokiGreen(), backgroundColor: .clear, target: self, selector: #selector(linkNewDevice)) + linkNewDeviceButton.setBackgroundColors(upColor: .clear, downColor: .clear) + linkNewDeviceButton.autoSetDimension(.height, toSize: linkNewDeviceButtonHeight) + linkNewDeviceButton.button.contentHorizontalAlignment = .left + let result = UIStackView(arrangedSubviews: [ explanationLabel, linkNewDeviceButton ]) + result.axis = .vertical + result.spacing = 4 + result.alignment = .center + return result + }() + + // MARK: Lifecycle + override func viewDidLoad() { + title = NSLocalizedString("Linked Devices", comment: "") + let masterDeviceHexEncodedPublicKey = UserDefaults.standard.string(forKey: "masterDeviceHexEncodedPublicKey") + let isMasterDevice = (masterDeviceHexEncodedPublicKey == nil) + if isMasterDevice { + navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(linkNewDevice)) + } + view.backgroundColor = Theme.backgroundColor + view.addSubview(tableView) + tableView.pin(to: view) + view.addSubview(callToActionView) + callToActionView.center(in: view) + updateDeviceLinks() + } + + // MARK: Data + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return deviceLinks.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! Cell + let deviceLink = deviceLinks[indexPath.row] + cell.deviceLink = deviceLink + return cell + } + + // MARK: Updating + private func updateDeviceLinks() { + let storage = OWSPrimaryStorage.shared() + let userHexEncodedPublicKey = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey + var deviceLinks: [DeviceLink] = [] + storage.dbReadConnection.read { transaction in + deviceLinks = storage.getDeviceLinks(for: userHexEncodedPublicKey, in: transaction).sorted { lhs, rhs in + return lhs.other.hexEncodedPublicKey > rhs.other.hexEncodedPublicKey + } + } + self.deviceLinks = deviceLinks + } + + private func updateUI() { + tableView.reloadData() + UIView.animate(withDuration: 0.25) { + self.callToActionView.isHidden = !self.deviceLinks.isEmpty + } + } + + func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { + updateDeviceLinks() + } + + func handleDeviceLinkingModalDismissed() { + // Do nothing + } + + // MARK: Interaction + @objc private func linkNewDevice() { + if deviceLinks.isEmpty { + let deviceLinkingModal = DeviceLinkingModal(mode: .master, delegate: nil) + deviceLinkingModal.modalPresentationStyle = .overFullScreen + present(deviceLinkingModal, animated: true, completion: nil) + } else { + let alert = UIAlertController(title: NSLocalizedString("Multi Device Limit Reached", comment: ""), message: NSLocalizedString("It's currently not allowed to link more than one device.", comment: ""), preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) + present(alert, animated: true, completion: nil) + } + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let deviceLink = deviceLinks[indexPath.row] + let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + sheet.addAction(UIAlertAction(title: NSLocalizedString("Change Name", comment: ""), style: .default) { [weak self] _ in + guard let self = self else { return } + let deviceNameModal = DeviceNameModal() + deviceNameModal.deviceLink = deviceLink + deviceNameModal.delegate = self + self.present(deviceNameModal, animated: true, completion: nil) + }) + sheet.addAction(UIAlertAction(title: NSLocalizedString("Unlink", comment: ""), style: .destructive) { _ in + // TODO: Implement + }) + present(sheet, animated: true, completion: nil) + } + + @objc func handleDeviceNameChanged(to name: String, for device: DeviceLink.Device) { + updateUI() + } +} + +// MARK: - Cell + +private extension DeviceLinksVC { + + final class Cell : UITableViewCell { + var deviceLink: DeviceLink! { didSet { update() } } + + // MARK: Components + private lazy var titleLabel: UILabel = { + let result = UILabel() + result.textColor = Theme.primaryColor + result.font = UIFont.ows_dynamicTypeSubheadlineClamped + result.lineBreakMode = .byTruncatingTail + return result + }() + + private lazy var subtitleLabel: UILabel = { + let result = UILabel() + result.textColor = Theme.primaryColor + result.font = UIFont.ows_dynamicTypeCaption1Clamped + result.lineBreakMode = .byTruncatingTail + return result + }() + + // MARK: Initialization + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setUpViewHierarchy() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUpViewHierarchy() + } + + private func setUpViewHierarchy() { + backgroundColor = .clear + let stackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel ]) + stackView.axis = .vertical + stackView.distribution = .equalCentering + stackView.spacing = 4 + stackView.set(.height, to: 36) + contentView.addSubview(stackView) + stackView.pin(.leading, to: .leading, of: contentView, withInset: 16) + stackView.pin(.top, to: .top, of: contentView, withInset: 8) + contentView.pin(.trailing, to: .trailing, of: stackView, withInset: 16) + contentView.pin(.bottom, to: .bottom, of: stackView, withInset: 8) + stackView.set(.width, to: UIScreen.main.bounds.width - 2 * 16) + } + + // MARK: Updating + private func update() { + if let displayName = deviceLink.displayName { + titleLabel.text = displayName + subtitleLabel.text = deviceLink.other.hexEncodedPublicKey + subtitleLabel.isHidden = false + } else { + titleLabel.text = deviceLink.other.hexEncodedPublicKey + subtitleLabel.isHidden = true + } + } + } +} diff --git a/Signal/src/Loki/Settings/DeviceNameModal.swift b/Signal/src/Loki/Settings/DeviceNameModal.swift new file mode 100644 index 000000000..5b3047652 --- /dev/null +++ b/Signal/src/Loki/Settings/DeviceNameModal.swift @@ -0,0 +1,64 @@ + +@objc(LKDeviceNameModal) +final class DeviceNameModal : Modal { + @objc public var deviceLink: DeviceLink! + @objc public var delegate: DeviceNameModalDelegate? + + // MARK: Components + private lazy var nameTextView: UITextField = { + let result = UITextField() + result.textColor = Theme.primaryColor + result.font = .ows_dynamicTypeBodyClamped + let placeholder = NSMutableAttributedString(string: NSLocalizedString("Enter a Name", comment: "")) + placeholder.addAttribute(.foregroundColor, value: Theme.placeholderColor, range: NSRange(location: 0, length: placeholder.length)) + result.attributedPlaceholder = placeholder + result.tintColor = .lokiGreen() + result.keyboardAppearance = .dark + return result + }() + + // MARK: Lifecycle + override func populateContentView() { + // Label + let titleLabel = UILabel() + titleLabel.textColor = Theme.primaryColor + titleLabel.font = UIFont.ows_dynamicTypeHeadlineClamped + titleLabel.text = NSLocalizedString("Change Device Name", comment: "") + titleLabel.numberOfLines = 0 + titleLabel.lineBreakMode = .byWordWrapping + titleLabel.textAlignment = .center + // Explanation label + let explanationLabel = UILabel() + explanationLabel.font = UIFont.ows_dynamicTypeCaption1Clamped + explanationLabel.text = NSLocalizedString("Enter the new display name for your device below", comment: "") + explanationLabel.numberOfLines = 0 + explanationLabel.textAlignment = .center + explanationLabel.lineBreakMode = .byWordWrapping + explanationLabel.textColor = UIColor.ows_white + // Button stack view + let okButton = OWSFlatButton.button(title: NSLocalizedString("OK", comment: ""), font: .ows_dynamicTypeBodyClamped, titleColor: .white, backgroundColor: .clear, target: self, selector: #selector(changeName)) + okButton.setBackgroundColors(upColor: .clear, downColor: .clear) + let buttonStackView = UIStackView(arrangedSubviews: [ okButton, cancelButton ]) + buttonStackView.axis = .horizontal + buttonStackView.distribution = .fillEqually + let buttonHeight = cancelButton.button.titleLabel!.font.pointSize * 48 / 17 + okButton.set(.height, to: buttonHeight) + cancelButton.set(.height, to: buttonHeight) + // Stack view + let stackView = UIStackView(arrangedSubviews: [ UIView.spacer(withHeight: 2), titleLabel, explanationLabel, nameTextView, buttonStackView ]) + stackView.axis = .vertical + stackView.spacing = 16 + contentView.addSubview(stackView) + stackView.pin(.leading, to: .leading, of: contentView, withInset: 16) + stackView.pin(.top, to: .top, of: contentView, withInset: 16) + contentView.pin(.trailing, to: .trailing, of: stackView, withInset: 16) + contentView.pin(.bottom, to: .bottom, of: stackView, withInset: 16) + } + + // MARK: Interaction + @objc private func changeName() { + let name = nameTextView.text!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + UserDefaults.standard.set(name, forKey: "\(deviceLink.other.hexEncodedPublicKey)_display_name") + delegate?.handleDeviceNameChanged(to: name, for: deviceLink.other) + } +} diff --git a/Signal/src/Loki/Settings/DeviceNameModalDelegate.swift b/Signal/src/Loki/Settings/DeviceNameModalDelegate.swift new file mode 100644 index 000000000..ad67f8237 --- /dev/null +++ b/Signal/src/Loki/Settings/DeviceNameModalDelegate.swift @@ -0,0 +1,5 @@ + +@objc protocol DeviceNameModalDelegate { + + func handleDeviceNameChanged(to name: String, for device: DeviceLink.Device) +} diff --git a/Signal/src/Loki/Settings/NukeDataModal.swift b/Signal/src/Loki/Settings/NukeDataModal.swift index 936ddb59a..98dcfaaa1 100644 --- a/Signal/src/Loki/Settings/NukeDataModal.swift +++ b/Signal/src/Loki/Settings/NukeDataModal.swift @@ -1,4 +1,3 @@ -import NVActivityIndicatorView @objc(LKNukeDataModal) final class NukeDataModal : Modal { diff --git a/Signal/src/Loki/Utilities/UIView+Constraint.swift b/Signal/src/Loki/Utilities/UIView+Constraint.swift index 55d1d26c3..9d1daa546 100644 --- a/Signal/src/Loki/Utilities/UIView+Constraint.swift +++ b/Signal/src/Loki/Utilities/UIView+Constraint.swift @@ -45,6 +45,11 @@ extension UIView { } } + func center(in view: UIView) { + center(.horizontal, in: view) + center(.vertical, in: view) + } + func set(_ dimension: Dimension, to size: CGFloat) { translatesAutoresizingMaskIntoConstraints = false switch dimension { diff --git a/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m b/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m index cd5373c3f..989275ad2 100644 --- a/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m +++ b/Signal/src/ViewControllers/AppSettings/AppSettingsViewController.m @@ -202,14 +202,13 @@ actionBlock:^{ [weakSelf showNotifications]; }]]; + [section addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"Linked Devices", @"") + accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"linked_devices") + actionBlock:^{ + [weakSelf showLinkedDevices]; + }]]; // Loki: Original code // ======== -// [section addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"LINKED_DEVICES_TITLE", -// @"Menu item and navbar title for the device manager") -// accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"linked_devices") -// actionBlock:^{ -// [weakSelf showLinkedDevices]; -// }]]; // [section addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"SETTINGS_ADVANCED_TITLE", @"") // accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"advanced") // actionBlock:^{ @@ -248,25 +247,6 @@ [section addItem:[OWSTableItem itemWithTitle:NSLocalizedString(@"Share Public Key", @"") actionBlock:^{ [weakSelf sharePublicKey]; }]]; [section addItem:[OWSTableItem itemWithTitle:NSLocalizedString(@"Show QR Code", @"") actionBlock:^{ [weakSelf showQRCode]; }]]; - if (isMasterDevice) { - NSString *userHexEncodedPublicKey = OWSIdentityManager.sharedManager.identityKeyPair.hexEncodedPublicKey; - __block BOOL hasLinkedDevice; - [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - NSSet *deviceLinks = [LKDatabaseUtilities getDeviceLinksFor:userHexEncodedPublicKey in:transaction]; - hasLinkedDevice = deviceLinks.count > 0; - }]; - [section addItem:[OWSTableItem itemWithTitle:NSLocalizedString(@"Link Device", @"") actionBlock:^{ - if (!hasLinkedDevice) { - [weakSelf linkDevice]; - } else { - UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Multi Device Limit Reached", @"") message:NSLocalizedString(@"It's currently not allowed to link more than one device.", @"") preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"") style:UIAlertActionStyleDefault handler:nil]]; - [weakSelf presentViewController:alert animated:YES completion:nil]; - } - }]]; - - [section addItem:[OWSTableItem itemWithTitle:NSLocalizedString(@"Show Seed", @"") actionBlock:^{ [weakSelf showSeed]; }]]; - } [section addItem:[OWSTableItem itemWithTitle:NSLocalizedString(@"Clear All Data", @"") actionBlock:^{ [weakSelf clearAllData]; }]]; if (TSAccountManager.sharedInstance.isDeregistered) { @@ -429,8 +409,8 @@ - (void)showLinkedDevices { - OWSLinkedDevicesTableViewController *vc = [OWSLinkedDevicesTableViewController new]; - [self.navigationController pushViewController:vc animated:YES]; + LKDeviceLinksVC *deviceLinksVC = [LKDeviceLinksVC new]; + [self.navigationController pushViewController:deviceLinksVC animated:YES]; } - (void)showProfile @@ -542,13 +522,6 @@ [self presentViewController:qrCodeModal animated:YES completion:nil]; } -- (void)linkDevice -{ - LKDeviceLinkingModal *deviceLinkingModal = [[LKDeviceLinkingModal alloc] initWithMode:@"master" delegate:nil]; - deviceLinkingModal.modalPresentationStyle = UIModalPresentationOverFullScreen; - [self presentViewController:deviceLinkingModal animated:YES completion:nil]; -} - - (void)showSeed { LKSeedModal *seedModal = [LKSeedModal new]; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 64d1d82c2..f98025fe2 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -2655,3 +2655,11 @@ "Clear Profile Picture" = "Clear Profile Picture"; "Invalid QR Code" = "Invalid QR Code"; "Please make sure the QR code you scanned is correct and try again." = "Please make sure the QR code you scanned is correct and try again."; +"Linked Devices" = "Linked Devices"; +"You don't have any linked devices yet" = "You don't have any linked devices yet"; +"Link a Device" = "Link a Device"; +"Unlink" = "Unlink"; +"Change Name" = "Change Name"; +"Change Device Name" = "Change Device Name"; +"Enter the new display name for your device below" = "Enter the new display name for your device below"; +"Enter a Name" = "Enter a Name"; diff --git a/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift b/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift index c194c5790..d21b73d27 100644 --- a/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift +++ b/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift @@ -4,8 +4,21 @@ public final class DeviceLink : NSObject, NSCoding { @objc public let master: Device @objc public let slave: Device + @objc public var displayName: String? { + if let customDisplayName = UserDefaults.standard.string(forKey: "\(other.hexEncodedPublicKey)_display_name") { + return customDisplayName + } else { + return Mnemonic.encode(hexEncodedString: other.hexEncodedPublicKey.removing05PrefixIfNeeded()).split(separator: " ")[0..<3].joined(separator: " ") + } + } + @objc public var isAuthorized: Bool { return master.signature != nil } + @objc public var other: Device { + let userHexEncodedPublicKey = OWSIdentityManager.shared().identityKeyPair()!.hexEncodedPublicKey + return (userHexEncodedPublicKey == master.hexEncodedPublicKey) ? slave : master + } + // MARK: Types @objc(LKDevice) public final class Device : NSObject, NSCoding {