diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 317fe4580..267c7ba11 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -574,7 +574,6 @@ C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C59247F214E001123EF /* UIView+Glow.swift */; }; C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */; }; C34C8F7423A7830B00D82669 /* SpaceMono-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */; }; - C353F8F7244808E90011121A /* PNModeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C353F8F6244808E90011121A /* PNModeSheet.swift */; }; C353F8F9244809150011121A /* PNOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C353F8F8244809150011121A /* PNOptionView.swift */; }; C3548F0624456447009433A8 /* PNModeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0524456447009433A8 /* PNModeVC.swift */; }; C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */; }; @@ -584,6 +583,7 @@ C35E8AA92485C85800ACB629 /* GeoLite2-Country-Blocks-IPv4.csv in Resources */ = {isa = PBXBuildFile; fileRef = C35E8AA62485C85600ACB629 /* GeoLite2-Country-Blocks-IPv4.csv */; }; C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = C35E8AAD2485E51D00ACB629 /* IP2Country.swift */; }; C3638C0524C7F0B500AF29BC /* LK002RemoveFriendRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3638C0424C7F0B500AF29BC /* LK002RemoveFriendRequests.swift */; }; + C369549D24D27A3500CEB4E3 /* MultiDeviceRemovalSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C369549C24D27A3500CEB4E3 /* MultiDeviceRemovalSheet.swift */; }; C36B8707243C50C60049991D /* SignalMessaging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 453518921FC63DBF00210559 /* SignalMessaging.framework */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; }; C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; }; @@ -1362,7 +1362,6 @@ C31A6C59247F214E001123EF /* UIView+Glow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Glow.swift"; sourceTree = ""; }; C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGRect+Utilities.swift"; sourceTree = ""; }; C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SpaceMono-Bold.ttf"; sourceTree = ""; }; - C353F8F6244808E90011121A /* PNModeSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeSheet.swift; sourceTree = ""; }; C353F8F8244809150011121A /* PNOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNOptionView.swift; sourceTree = ""; }; C3548F0524456447009433A8 /* PNModeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeVC.swift; sourceTree = ""; }; C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Wrapping.swift"; sourceTree = ""; }; @@ -1372,6 +1371,7 @@ C35E8AA62485C85600ACB629 /* GeoLite2-Country-Blocks-IPv4.csv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "GeoLite2-Country-Blocks-IPv4.csv"; sourceTree = ""; }; C35E8AAD2485E51D00ACB629 /* IP2Country.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IP2Country.swift; sourceTree = ""; }; C3638C0424C7F0B500AF29BC /* LK002RemoveFriendRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LK002RemoveFriendRequests.swift; sourceTree = ""; }; + C369549C24D27A3500CEB4E3 /* MultiDeviceRemovalSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiDeviceRemovalSheet.swift; sourceTree = ""; }; C3AA6BB824CE8F1B002358B6 /* Migrating Translations from Android.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Migrating Translations from Android.md"; sourceTree = ""; }; C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = ""; }; C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = ""; }; @@ -2710,12 +2710,12 @@ B85357C423A1F13800AAF6CD /* LinkDeviceVC.swift */, B85357C623A1FB5100AAF6CD /* LinkDeviceVCDelegate.swift */, B86BD08323399ACF000F5AE3 /* Modal.swift */, + C369549C24D27A3500CEB4E3 /* MultiDeviceRemovalSheet.swift */, B80A579E23DFF1F300876683 /* NewClosedGroupVC.swift */, B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */, B894D0742339EDCF00B4D94D /* NukeDataModal.swift */, C3DFFAC723E970080058DAF8 /* OpenGroupSuggestionSheet.swift */, B879D448247E1BE300DB3608 /* PathVC.swift */, - C353F8F6244808E90011121A /* PNModeSheet.swift */, C3548F0524456447009433A8 /* PNModeVC.swift */, B886B4A62398B23E00211ABE /* QRCodeVC.swift */, B82B408B239A068800A248E7 /* RegisterVC.swift */, @@ -3801,7 +3801,6 @@ 4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */, 4CB5F26720F6E1E2004D1B42 /* MenuActionsViewController.swift in Sources */, 3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */, - C353F8F7244808E90011121A /* PNModeSheet.swift in Sources */, 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */, 340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */, C3548F0624456447009433A8 /* PNModeVC.swift in Sources */, @@ -3848,6 +3847,7 @@ 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */, 4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */, 4CC1ECFB211A553000CC13BE /* AppUpdateNag.swift in Sources */, + C369549D24D27A3500CEB4E3 /* MultiDeviceRemovalSheet.swift in Sources */, 34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */, B8CCF639239721E20091D419 /* TabBar.swift in Sources */, 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */, diff --git a/Signal/src/Loki/View Controllers/HomeVC.swift b/Signal/src/Loki/View Controllers/HomeVC.swift index 39f913d70..eec8fefc7 100644 --- a/Signal/src/Loki/View Controllers/HomeVC.swift +++ b/Signal/src/Loki/View Controllers/HomeVC.swift @@ -177,12 +177,16 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) isViewVisible = true - let hasSeenPNModeSheet = UserDefaults.standard[.hasSeenPNModeSheet] - if !hasSeenPNModeSheet { - let pnModeSheet = PNModeSheet() - pnModeSheet.modalPresentationStyle = .overFullScreen - pnModeSheet.modalTransitionStyle = .crossDissolve - present(pnModeSheet, animated: true, completion: nil) + let hasSeenMultiDeviceRemovalSheet = UserDefaults.standard[.hasSeenMultiDeviceRemovalSheet] + if !hasSeenMultiDeviceRemovalSheet { + let _ = FileServerAPI.getDeviceLinks(associatedWith: getUserHexEncodedPublicKey()).done(on: DispatchQueue.main) { [weak self] deviceLinks in + guard !deviceLinks.isEmpty else { return } + let multiDeviceRemovalSheet = MultiDeviceRemovalSheet() + multiDeviceRemovalSheet.modalPresentationStyle = .overFullScreen + multiDeviceRemovalSheet.modalTransitionStyle = .crossDissolve + self?.present(multiDeviceRemovalSheet, animated: true, completion: nil) + } + UserDefaults.standard[.hasSeenMultiDeviceRemovalSheet] = true } UserDefaults.standard[.hasLaunchedOnce] = true } diff --git a/Signal/src/Loki/View Controllers/LandingVC.swift b/Signal/src/Loki/View Controllers/LandingVC.swift index 777ef0f98..51acccbac 100644 --- a/Signal/src/Loki/View Controllers/LandingVC.swift +++ b/Signal/src/Loki/View Controllers/LandingVC.swift @@ -59,11 +59,11 @@ final class LandingVC : BaseVC, LinkDeviceVCDelegate, DeviceLinkingModalDelegate // Set up link button container let linkButtonContainer = UIView() linkButtonContainer.set(.height, to: Values.onboardingButtonBottomOffset) - linkButtonContainer.addSubview(linkButton) - linkButton.pin(.leading, to: .leading, of: linkButtonContainer, withInset: Values.massiveSpacing) - linkButton.pin(.top, to: .top, of: linkButtonContainer) - linkButtonContainer.pin(.trailing, to: .trailing, of: linkButton, withInset: Values.massiveSpacing) - linkButtonContainer.pin(.bottom, to: .bottom, of: linkButton, withInset: isIPhone5OrSmaller ? 6 : 10) +// linkButtonContainer.addSubview(linkButton) +// linkButton.pin(.leading, to: .leading, of: linkButtonContainer, withInset: Values.massiveSpacing) +// linkButton.pin(.top, to: .top, of: linkButtonContainer) +// linkButtonContainer.pin(.trailing, to: .trailing, of: linkButton, withInset: Values.massiveSpacing) +// linkButtonContainer.pin(.bottom, to: .bottom, of: linkButton, withInset: isIPhone5OrSmaller ? 6 : 10) // Set up button stack view let buttonStackView = UIStackView(arrangedSubviews: [ registerButton, restoreButton ]) buttonStackView.axis = .vertical diff --git a/Signal/src/Loki/View Controllers/MultiDeviceRemovalSheet.swift b/Signal/src/Loki/View Controllers/MultiDeviceRemovalSheet.swift new file mode 100644 index 000000000..1391eb3ae --- /dev/null +++ b/Signal/src/Loki/View Controllers/MultiDeviceRemovalSheet.swift @@ -0,0 +1,93 @@ +import PromiseKit + +final class MultiDeviceRemovalSheet : Sheet { + + private lazy var removalDate: Date = { + let calendar = Calendar(identifier: .gregorian) + let timezone = TimeZone(identifier: "Australia/Melbourne") + let components = DateComponents(calendar: calendar, timeZone: timezone, year: 2020, month: 8, day: 6, hour: 17) + return calendar.date(from: components)! + }() + + private lazy var removalDateDescription: String = { + let formatter = DateFormatter() + formatter.dateFormat = "MMMM d" + return formatter.string(from: removalDate) + }() + + private lazy var explanation: String = { + if UserDefaults.standard[.masterHexEncodedPublicKey] != nil { + let format = """ + You’re seeing this because this is a secondary device in a multi-device setup. To improve reliability and stability, we’ve decided to temporarily disable Session’s multi-device functionality on %@. Device linking has been disabled, and the next update will erase existing secondary devices. + + To read more about this change, visit the Session FAQ at getsession.org/faq. + """ + return String(format: format, removalDateDescription) + } else { + let format = """ + You’re seeing this because you have a secondary device linked to your Session ID. To improve reliability and stability, we’ve decided to temporarily disable Session’s multi-device functionality on %@. Device linking has been disabled, and the next update will erase existing secondary devices. + + To read more about this change, visit the Session FAQ at getsession.org/faq + """ + return String(format: format, removalDateDescription) + } + }() + + private lazy var attributedExplanation: NSAttributedString = { + let result = NSMutableAttributedString(string: explanation) + result.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), range: (explanation as NSString).range(of: removalDateDescription)) + result.addAttribute(.foregroundColor, value: Colors.accent, range: (explanation as NSString).range(of: removalDateDescription)) + result.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.smallFontSize), range: (explanation as NSString).range(of: "getsession.org/faq")) + result.addAttribute(.foregroundColor, value: Colors.accent, range: (explanation as NSString).range(of: "getsession.org/faq")) + return result + }() + + private lazy var explanationLabel: UILabel = { + let result = UILabel() + result.textColor = Colors.text + result.font = .systemFont(ofSize: Values.smallFontSize) + result.attributedText = attributedExplanation + result.numberOfLines = 0 + result.lineBreakMode = .byWordWrapping + return result + }() + + override func populateContentView() { + // Set up title label + let titleLabel = UILabel() + titleLabel.textColor = Colors.text + titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) + titleLabel.text = "Changes to Multi-Device" + titleLabel.numberOfLines = 0 + titleLabel.lineBreakMode = .byWordWrapping + // Set up explanation label + explanationLabel.isUserInteractionEnabled = true + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleExplanationLabelTapped)) + explanationLabel.addGestureRecognizer(tapGestureRecognizer) + // Set up OK button + let okButton = Button(style: .prominentOutline, size: .large) + okButton.set(.width, to: 240) + okButton.setTitle(NSLocalizedString("OK", comment: ""), for: UIControl.State.normal) + okButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) + // Set up main stack view + let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel, okButton ]) + stackView.axis = .vertical + stackView.spacing = Values.veryLargeSpacing + stackView.alignment = .center + // Set up constraints + contentView.addSubview(stackView) + stackView.pin(.leading, to: .leading, of: contentView, withInset: Values.veryLargeSpacing) + stackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) + contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.veryLargeSpacing) + contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.veryLargeSpacing + overshoot) + } + + @objc private func handleExplanationLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) { + let range = (explanationLabel.text! as NSString).range(of: "getsession.org/faq") + let touchInExplanationLabelCoordinates = tapGestureRecognizer.location(in: explanationLabel) + let characterIndex = explanationLabel.characterIndex(for: touchInExplanationLabelCoordinates) + guard range.contains(characterIndex) else { return } + let url = URL(string: "https://getsession.org/faq")! + UIApplication.shared.open(url) + } +} diff --git a/Signal/src/Loki/View Controllers/PNModeSheet.swift b/Signal/src/Loki/View Controllers/PNModeSheet.swift deleted file mode 100644 index 1ddf9b6c9..000000000 --- a/Signal/src/Loki/View Controllers/PNModeSheet.swift +++ /dev/null @@ -1,89 +0,0 @@ -import PromiseKit - -final class PNModeSheet : Sheet, OptionViewDelegate { - - private var optionViews: [OptionView] { - [ apnsOptionView, backgroundPollingOptionView ] - } - - private var selectedOptionView: OptionView? { - return optionViews.first { $0.isSelected } - } - - // MARK: Components - private lazy var apnsOptionView = OptionView(title: NSLocalizedString("Apple Push Notification Service", comment: ""), explanation: NSLocalizedString("Session will use the Apple Push Notification service to receive push notifications. You'll be notified of new messages reliably and immediately. Using APNs means that your IP address and device token will be exposed to Apple. If you use push notifications for other apps, this will already be the case. Your IP address and device token will also be exposed to Loki, but your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.", comment: ""), delegate: self, isRecommended: true) - private lazy var backgroundPollingOptionView = OptionView(title: NSLocalizedString("Background Polling", comment: ""), explanation: NSLocalizedString("Session will occasionally check for new messages in the background. This guarantees full metadata protection, but message notifications may be significantly delayed.", comment: ""), delegate: self) - - // MARK: Lifecycle - override func populateContentView() { - // Set up title label - let titleLabel = UILabel() - titleLabel.textColor = Colors.text - titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize) - titleLabel.text = NSLocalizedString("Push Notifications", comment: "") - titleLabel.numberOfLines = 0 - titleLabel.lineBreakMode = .byWordWrapping - // Set up explanation label - let explanationLabel = UILabel() - explanationLabel.textColor = Colors.text - explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) - explanationLabel.text = NSLocalizedString("Session now features two ways to handle push notifications. Make sure to read the descriptions carefully before you choose.", comment: "") - explanationLabel.numberOfLines = 0 - explanationLabel.lineBreakMode = .byWordWrapping - // Set up options stack view - let optionsStackView = UIStackView(arrangedSubviews: optionViews) - optionsStackView.axis = .vertical - optionsStackView.spacing = Values.smallSpacing - optionsStackView.alignment = .fill - // Set up confirm button - let confirmButton = Button(style: .prominentOutline, size: .medium) - confirmButton.set(.width, to: 240) - confirmButton.setTitle(NSLocalizedString("Confirm", comment: ""), for: UIControl.State.normal) - confirmButton.addTarget(self, action: #selector(confirm), for: UIControl.Event.touchUpInside) - // Set up dismiss button - let skipButton = Button(style: .regular, size: .medium) - skipButton.set(.width, to: 240) - skipButton.setTitle(NSLocalizedString("Skip", comment: ""), for: UIControl.State.normal) - skipButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside) - // Set up button stack view - let bottomStackView = UIStackView(arrangedSubviews: [ confirmButton, skipButton ]) - bottomStackView.axis = .vertical - bottomStackView.spacing = isIPhone5OrSmaller ? Values.smallSpacing : Values.mediumSpacing - bottomStackView.alignment = .fill - // Set up main stack view - let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel, optionsStackView, bottomStackView ]) - stackView.axis = .vertical - stackView.spacing = isIPhone5OrSmaller ? 12 : Values.largeSpacing - stackView.alignment = .center - // Set up constraints - contentView.addSubview(stackView) - stackView.pin(.leading, to: .leading, of: contentView, withInset: isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) - stackView.pin(.top, to: .top, of: contentView, withInset: isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) - contentView.pin(.trailing, to: .trailing, of: stackView, withInset: isIPhone5OrSmaller ? Values.mediumSpacing : Values.largeSpacing) - contentView.pin(.bottom, to: .bottom, of: stackView, withInset: (isIPhone5OrSmaller ? Values.mediumSpacing : Values.veryLargeSpacing) + overshoot) - } - - // MARK: Interaction - func optionViewDidActivate(_ optionView: OptionView) { - optionViews.filter { $0 != optionView }.forEach { $0.isSelected = false } - } - - @objc private func confirm() { - guard selectedOptionView != nil else { - let title = NSLocalizedString("Please Pick an Option", comment: "") - let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil)) - return present(alert, animated: true, completion: nil) - } - UserDefaults.standard[.isUsingFullAPNs] = (selectedOptionView == apnsOptionView) - let syncTokensJob = SyncPushTokensJob(accountManager: AppEnvironment.shared.accountManager, preferences: Environment.shared.preferences) - syncTokensJob.uploadOnlyIfStale = false - let _: Promise = syncTokensJob.run() - close() - } - - override func close() { - UserDefaults.standard[.hasSeenPNModeSheet] = true - super.close() - } -} diff --git a/Signal/src/Loki/View Controllers/PNModeVC.swift b/Signal/src/Loki/View Controllers/PNModeVC.swift index ab16bfee2..f2293b421 100644 --- a/Signal/src/Loki/View Controllers/PNModeVC.swift +++ b/Signal/src/Loki/View Controllers/PNModeVC.swift @@ -89,7 +89,7 @@ final class PNModeVC : BaseVC, OptionViewDelegate { return present(alert, animated: true, completion: nil) } UserDefaults.standard[.isUsingFullAPNs] = (selectedOptionView == apnsOptionView) - UserDefaults.standard[.hasSeenPNModeSheet] = true // Shouldn't be shown to users who've done the new onboarding + UserDefaults.standard[.hasSeenMultiDeviceRemovalSheet] = true TSAccountManager.sharedInstance().didRegister() let homeVC = HomeVC() navigationController!.setViewControllers([ homeVC ], animated: true) diff --git a/Signal/src/Loki/View Controllers/SettingsVC.swift b/Signal/src/Loki/View Controllers/SettingsVC.swift index 8e2976a25..518a67001 100644 --- a/Signal/src/Loki/View Controllers/SettingsVC.swift +++ b/Signal/src/Loki/View Controllers/SettingsVC.swift @@ -167,8 +167,8 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate { ] let isMasterDevice = UserDefaults.standard.isMasterDevice if isMasterDevice { - result.append(getSeparator()) - result.append(getSettingButton(withTitle: NSLocalizedString("vc_settings_devices_button_title", comment: ""), color: Colors.text, action: #selector(showLinkedDevices))) +// result.append(getSeparator()) +// result.append(getSettingButton(withTitle: NSLocalizedString("vc_settings_devices_button_title", comment: ""), color: Colors.text, action: #selector(showLinkedDevices))) result.append(getSeparator()) result.append(getSettingButton(withTitle: NSLocalizedString("vc_settings_recovery_phrase_button_title", comment: ""), color: Colors.text, action: #selector(showSeed))) } diff --git a/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift b/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift index ca4039e08..21ab9158d 100644 --- a/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift +++ b/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift @@ -5,8 +5,8 @@ public enum LKUserDefaults { public enum Bool : Swift.String { case hasLaunchedOnce case hasSeenGIFMetadataWarning + case hasSeenMultiDeviceRemovalSheet case hasSeenOpenGroupSuggestionSheet - case hasSeenPNModeSheet case hasViewedSeed /// Whether the device was unlinked as a slave device (used to notify the user on the landing screen). case wasUnlinked