Tweak the flow for changing a recovery key. (#3452)

* Rename Chat Backup setting to Encryption.

* Update Key Storage strings on SecureBackupScreen.

* Update strings/design on SecureBackupRecoveryKeyScreen.
This commit is contained in:
Doug
2024-10-28 12:28:13 +00:00
committed by GitHub
parent 948575ec79
commit 53409230c8
43 changed files with 175 additions and 116 deletions

View File

@@ -27,6 +27,7 @@ struct SecureBackupRecoveryKeyScreenViewState: BindableState {
let mode: SecureBackupRecoveryKeyScreenViewMode
var recoveryKey: String?
var isGeneratingKey = false
var doneButtonEnabled = false
var bindings: SecureBackupRecoveryKeyScreenViewBindings

View File

@@ -49,6 +49,8 @@ class SecureBackupRecoveryKeyScreenViewModel: SecureBackupRecoveryKeyScreenViewM
switch viewAction {
case .generateKey:
state.isGeneratingKey = true
Task {
switch await secureBackupController.generateRecoveryKey() {
case .success(let key):
@@ -58,7 +60,7 @@ class SecureBackupRecoveryKeyScreenViewModel: SecureBackupRecoveryKeyScreenViewM
state.bindings.alertInfo = .init(id: .init())
}
hideLoadingIndicator()
state.isGeneratingKey = false
}
case .copyKey:
UIPasteboard.general.string = state.recoveryKey

View File

@@ -18,7 +18,6 @@ struct SecureBackupRecoveryKeyScreen: View {
FullscreenDialog {
ScrollViewReader { reader in
mainContent
.padding(16)
.onChange(of: focused) { _, newValue in
guard newValue == true else { return }
reader.scrollTo(textFieldIdentifier)
@@ -94,12 +93,12 @@ struct SecureBackupRecoveryKeyScreen: View {
}
private var recoveryCreatedActionButtons: some View {
VStack(spacing: 8.0) {
VStack(spacing: 16) {
if let recoveryKey = context.viewState.recoveryKey {
ShareLink(item: recoveryKey) {
Label(L10n.screenRecoveryKeySaveAction, icon: \.download)
}
.buttonStyle(.compound(.primary))
.buttonStyle(.compound(.secondary))
.simultaneousGesture(TapGesture().onEnded { _ in
context.send(viewAction: .keySaved)
})
@@ -131,20 +130,31 @@ struct SecureBackupRecoveryKeyScreen: View {
Text(L10n.commonRecoveryKey)
.foregroundColor(.compound.textPrimary)
.font(.compound.bodySMSemibold)
.padding(.leading, 16)
Group {
if context.viewState.recoveryKey == nil {
Button(generateButtonTitle) {
context.send(viewAction: .generateKey)
if !context.viewState.isGeneratingKey {
Button(generateButtonTitle) {
context.send(viewAction: .generateKey)
}
.font(.compound.bodyLGSemibold)
.padding(.vertical, 11)
} else {
HStack(spacing: 8) {
ProgressView()
Text(L10n.screenRecoveryKeyGeneratingKey)
}
.font(.compound.bodyLGSemibold)
.foregroundStyle(.compound.textPrimary)
.padding(.vertical, 11)
}
.font(.compound.bodyLGSemibold)
} else {
HStack(alignment: .top, spacing: 8) {
HStack(spacing: 8) {
Text(context.viewState.recoveryKey ?? "")
.foregroundColor(.compound.textPrimary)
.font(.compound.bodyLG)
Spacer()
.frame(maxWidth: .infinity, alignment: .leading)
Button {
context.send(viewAction: .copyKey)
@@ -157,21 +167,16 @@ struct SecureBackupRecoveryKeyScreen: View {
}
}
.frame(maxWidth: .infinity)
.padding()
.padding(.vertical, 14)
.padding(.horizontal, 16)
.background(Color.compound.bgSubtleSecondaryLevel0)
.clipShape(RoundedRectangle(cornerRadius: 8))
.clipShape(RoundedRectangle(cornerRadius: 14))
if let subtitle = context.viewState.recoveryKeySubtitle {
Label {
Text(subtitle)
.foregroundColor(.compound.textSecondary)
.font(.compound.bodySM)
} icon: {
if context.viewState.recoveryKey == nil {
CompoundIcon(\.infoSolid, size: .small, relativeTo: .compound.bodySM)
}
}
.labelStyle(.custom(spacing: 8, alignment: .top))
Text(subtitle)
.foregroundColor(.compound.textSecondary)
.font(.compound.bodySM)
.padding(.leading, 16)
}
}
}
@@ -212,8 +217,10 @@ struct SecureBackupRecoveryKeyScreen: View {
// MARK: - Previews
struct SecureBackupRecoveryKeyScreen_Previews: PreviewProvider, TestablePreview {
static let setupViewModel = viewModel(recoveryState: .enabled)
static let key = "EsTM njec uHYA yHmh dQdW Nj4o bNRU 9jMN XGMc KUNM UFr5 R8GY"
static let notSetUpViewModel = viewModel(recoveryState: .disabled)
static let generatingViewModel = viewModel(recoveryState: .disabled, generateKey: true)
static let setupViewModel = viewModel(recoveryState: .enabled, generateKey: true, key: key)
static let incompleteViewModel = viewModel(recoveryState: .incomplete)
static let unknownViewModel = viewModel(recoveryState: .unknown)
@@ -223,10 +230,17 @@ struct SecureBackupRecoveryKeyScreen_Previews: PreviewProvider, TestablePreview
}
.previewDisplayName("Not set up")
NavigationStack {
SecureBackupRecoveryKeyScreen(context: generatingViewModel.context)
}
.previewDisplayName("Generating")
.snapshot(delay: 0.25)
NavigationStack {
SecureBackupRecoveryKeyScreen(context: setupViewModel.context)
}
.previewDisplayName("Set up")
.snapshot(delay: 0.25)
NavigationStack {
SecureBackupRecoveryKeyScreen(context: incompleteViewModel.context)
@@ -239,12 +253,27 @@ struct SecureBackupRecoveryKeyScreen_Previews: PreviewProvider, TestablePreview
.previewDisplayName("Unknown")
}
static func viewModel(recoveryState: SecureBackupRecoveryState) -> SecureBackupRecoveryKeyScreenViewModelType {
static func viewModel(recoveryState: SecureBackupRecoveryState, generateKey: Bool = false, key: String? = nil) -> SecureBackupRecoveryKeyScreenViewModelType {
let backupController = SecureBackupControllerMock()
backupController.underlyingRecoveryState = CurrentValueSubject<SecureBackupRecoveryState, Never>(recoveryState).asCurrentValuePublisher()
return SecureBackupRecoveryKeyScreenViewModel(secureBackupController: backupController,
userIndicatorController: UserIndicatorControllerMock(),
isModallyPresented: true)
if let key {
backupController.generateRecoveryKeyReturnValue = .success(key)
} else {
backupController.generateRecoveryKeyClosure = {
try? await Task.sleep(for: .seconds(1000))
return .success("youshouldntseeme")
}
}
let viewModel = SecureBackupRecoveryKeyScreenViewModel(secureBackupController: backupController,
userIndicatorController: UserIndicatorControllerMock(),
isModallyPresented: true)
if generateKey {
viewModel.context.send(viewAction: .generateKey)
}
return viewModel
}
}

View File

@@ -16,14 +16,15 @@ struct SecureBackupScreenViewState: BindableState {
let chatBackupDetailsURL: URL
var recoveryState = SecureBackupRecoveryState.unknown
var keyBackupState = SecureBackupKeyBackupState.unknown
var bindings = SecureBackupScreenViewStateBindings()
var bindings: SecureBackupScreenViewStateBindings
}
struct SecureBackupScreenViewStateBindings {
var keyStorageEnabled: Bool
var alertInfo: AlertInfo<UUID>?
}
enum SecureBackupScreenViewAction {
case recoveryKey
case keyBackup
case keyStorageToggled(Bool)
}

View File

@@ -25,7 +25,8 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
self.secureBackupController = secureBackupController
self.userIndicatorController = userIndicatorController
super.init(initialViewState: .init(chatBackupDetailsURL: chatBackupDetailsURL))
super.init(initialViewState: .init(chatBackupDetailsURL: chatBackupDetailsURL,
bindings: SecureBackupScreenViewStateBindings(keyStorageEnabled: secureBackupController.keyBackupState.value.toggleState)))
secureBackupController.recoveryState
.receive(on: DispatchQueue.main)
@@ -34,7 +35,11 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
secureBackupController.keyBackupState
.receive(on: DispatchQueue.main)
.weakAssign(to: \.state.keyBackupState, on: self)
.sink { [weak self] state in
guard let self else { return }
self.state.keyBackupState = state
self.state.bindings.keyStorageEnabled = state.toggleState
}
.store(in: &cancellables)
}
@@ -44,11 +49,14 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
switch viewAction {
case .recoveryKey:
actionsSubject.send(.recoveryKey)
case .keyBackup:
switch secureBackupController.keyBackupState.value {
case .unknown:
case .keyStorageToggled(let enable):
let keyBackupState = secureBackupController.keyBackupState.value
switch (keyBackupState, enable) {
case (.unknown, true):
state.bindings.keyStorageEnabled = keyBackupState.toggleState // Reset the toggle in case enabling fails
enableBackup()
case .enabled:
case (.enabled, false):
state.bindings.keyStorageEnabled = keyBackupState.toggleState // Reset the toggle in case the user cancels
actionsSubject.send(.keyBackup)
default:
break
@@ -74,3 +82,12 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
}
}
}
private extension SecureBackupKeyBackupState {
var toggleState: Bool {
switch self {
case .unknown, .enabling: false
case .enabled, .disabling: true
}
}
}

View File

@@ -39,7 +39,7 @@ struct SecureBackupScreen: View {
private var keyBackupSection: some View {
Section {
ListRow(kind: .custom {
VStack(alignment: .leading, spacing: 2) {
VStack(alignment: .leading, spacing: 8) {
Text(L10n.screenChatBackupKeyBackupTitle)
.font(.compound.bodyLGSemibold)
.foregroundColor(.compound.textPrimary)
@@ -53,7 +53,7 @@ struct SecureBackupScreen: View {
.accessibilityElement(children: .combine)
})
keyBackupButton
keyStorageToggle
}
}
@@ -67,26 +67,23 @@ struct SecureBackupScreen: View {
return description
}
@ViewBuilder
private var keyBackupButton: some View {
switch context.viewState.keyBackupState {
case .enabled, .disabling:
ListRow(label: .plain(title: L10n.screenChatBackupKeyBackupActionDisable, role: .destructive), kind: .navigationLink {
context.send(viewAction: .keyBackup)
})
case .unknown, .enabling:
ListRow(label: .plain(title: L10n.screenChatBackupKeyBackupActionEnable), kind: .navigationLink {
context.send(viewAction: .keyBackup)
})
}
private var keyStorageToggle: some View {
ListRow(label: .plain(title: L10n.screenChatBackupKeyStorageToggleTitle,
description: L10n.screenChatBackupKeyStorageToggleDescription),
kind: .toggle($context.keyStorageEnabled))
.onChange(of: context.keyStorageEnabled) { _, newValue in
context.send(viewAction: .keyStorageToggled(newValue))
}
}
@ViewBuilder
private var recoveryKeySection: some View {
Section {
switch context.viewState.recoveryState {
case .enabled:
ListRow(label: .plain(title: L10n.screenChatBackupRecoveryActionChange),
ListRow(label: .default(title: L10n.screenChatBackupRecoveryActionChange,
description: L10n.screenChatBackupRecoveryActionChangeDescription,
icon: \.key,
iconAlignment: .top),
kind: .navigationLink { context.send(viewAction: .recoveryKey) })
case .disabled:
ListRow(label: .plain(title: L10n.screenChatBackupRecoveryActionSetup),

View File

@@ -90,7 +90,7 @@ struct SettingsScreen: View {
switch context.viewState.securitySectionMode {
case .secureBackup:
ListRow(label: .default(title: L10n.commonChatBackup,
ListRow(label: .default(title: L10n.commonEncryption,
icon: \.key),
details: context.viewState.showSecuritySectionBadge ? .icon(securitySectionBadge) : nil,
kind: .navigationLink { context.send(viewAction: .secureBackup) })

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:42456c30e4c48f49498df5fb78543864ba73475b0519bb845fd8aea2b2711d2e
size 122723

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:18b21094daf27f491931edd1113b76f188c99f3558271208195792db24eea2ad
size 105484
oid sha256:40ae027d4a68aa576e6c09b86612f26a20287b78feee68828df22a9e75e8d4c0
size 105493

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:13771e53bc8396d5ad1af3119b78c031f0aa64fcc015e72e45c1e2b712846fd2
size 125802
oid sha256:d812c0830f2b0b88db0eba82fcbceb9b4c5698e7c55ad0e9e7fc5a9c83e96249
size 123915

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:61ec65771fe434a6c34ea47e015ce32f59521c5c86389c0e3989affc155c7c42
size 124896
oid sha256:2b4eb7771b9156b75c3812751b1219ba337e4d9b1b465dedd09e7784b1f009e9
size 120296

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f0bdd1681f7a87bae31a601bcf4a2e0df62730a8532169505b2aabab3ab6e982
size 78759
oid sha256:a8b27413a8893ca1b9797bb349f109a78b99a20eda69e385120d68793254f4dd
size 78755

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:af3a401be4780e063d611293d06988524e07ea45bd4558d51d0f4f0a937ce531
size 150029

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1bc60a89d5aede42baa7c36eafafe88f326712713551c4c738cf8d0cf3a7860c
size 121893
oid sha256:bd327eb2290a77139a8a3f3d76e99baf7f09d724034c5931dda0485ed2455136
size 120592

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8756534bad47d59f637ed3ed5cdde23bd88c58748e6f44df2edf8b4d325e3c27
size 157434
oid sha256:1500a5f539dc2ec3faae11c0d5a707f4329a15814d686de570baa901e1420fdf
size 151948

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2b4ceabdf84f86616791951043844e9c618b56b074f16adc97d95bf7418a0d3a
size 151871
oid sha256:e80a71b9eaeb41bd700cf22e98b0290c06e6786cdffea72c0973549b4ba5bd43
size 141940

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:625728b535938291ee7433c2e42c356f5984d59ec9c564b7ec114915cc604f30
size 80957
oid sha256:f690078660851b4af18ea78341b352c33f2862b378a19534010dbebe767f8b31
size 80936

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d1b0c218ffb7143d8da4567a02fa0741a94942449dd00c065b7415978a100e6d
size 76017

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:60ea8f1f8c02fc5f820a3b41fa4fe411124fdfb73c2fd51e771c51673becfbfd
size 61760
oid sha256:e264708e7ac73c422bf9f13ace0e5f590958f307deab7e89b18da0b724c76638
size 60695

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:15ab57d4af84466b82204b0dbb737e38d2c705ccfade6371494842108458b1bd
size 82439
oid sha256:6ba57bc91e2ca37583848b7127ebb0e6efc9f932cee136e596af6bd9f762490b
size 77531

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cf7b9fec4e99a3d71f9f9f704608f8209239ee1d0a2f89144a720be12bb1f433
size 80121
oid sha256:872d515fe6aae36c12d21a3e6757abcddf9e03e51e6421324505a528b5946376
size 74557

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a22acba2b438aeee6a26703ffafd346972c5ac764834a27b0542fed65298109d
size 37602
oid sha256:bcf8ffb5e43fa810a9f6b4bdbcd837bde6263923a13d6a7d961a494cccace95f
size 37582

View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3dee45d086663e3348733885a809a68e3f86cc33c70ca4e49676daa04f8dcd02
size 100956

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d67b8defaedb1ebd72d37fe40b52f70005cc1104be0e0d67a703c56fe337f98f
size 81282
oid sha256:ea13695902f6a63b2ccac8fa1c9de60d15091bc40274482383d09464c3d31e7d
size 80944

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a56bda1df5ee99fda29529826a288747634a1922b4bc4bcf544fd86a9e2097fc
size 118514
oid sha256:d6506e821995ed525758a557e0dc64c57c3331267c37cd4bcea742fc244cc435
size 106296

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c10cc0a97a467368cac68fac0c2a67f1a68050e755349c7b008ba1bd7098853
size 114487
oid sha256:88b07c92a3f9763eb361918da508af0e140bce7241ebbc92c38f3ac38cc9394d
size 100293

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6122ab324601debec8c3374c937852d0fef80951ad3771fa06f8b8db914bef18
size 42478
oid sha256:79fe4f39dcbd5438aa2d673e50e3efe24e2c5a4ea862684ff314c5d855ea486d
size 41923

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3afffdf37c3f24cc5c8c331faac191d39e4838ec21c6695702f38b625888b937
size 105856
oid sha256:41207583349f9c70c02e9f37482445511c597f46d150f6a2c289f0fd731c580b
size 138178

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2f262cd4362c5ea4d12f341badee0e253bb40c572fe5c9a8f0c8e24e8ae97b1e
size 98930
oid sha256:4574b56fd9c50e2146d6675881dd544e00d9f6ca4b8fa30beed4d42160f833f1
size 115816

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b2f5bbe38921c7ea09aa97c0a50fb73342dd7594fdabfd758b23cbc02d3f4403
size 117500
oid sha256:0b2432ac9ec6980dfa6618409a401d3a18474c73e37f49b5e29ba3b0dd1d0da0
size 134492

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:573167b53caef5932d4f65bde0f5b2464bcfe8fe1321215af93ab5df82ad460f
size 115876
oid sha256:53c980680e3a15a67fb5bea95819d42da84dac6c15d346dec0e6e79107a3f3fe
size 169146

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3a6cf656cead4fb620fd4fb9acd0d4038f0e75de1a9c3963d5394907ccb33664
size 107128
oid sha256:bc7cb971fef0b09290cd1296b67df22d792634a0f7ff48121e2432e1541ecfff
size 133858

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b04cdd32066178398a510f3300457171f6b020a8e37aaf30facd743618cf3e2e
size 137128
oid sha256:b08d094fbf0ca9f671a804a6894659ad9de40f10d376b1903f0449240dd0cf17
size 163516

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a4e365693e03873237cd2ce745731b4e41470dc2601e6ffa807da65ff7e2d206
size 57067
oid sha256:d297f54924748f5aa9d03852553f953647b2d18437a0e598371796fd006f33f5
size 93416

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5f51290abdc155242eafc3918e2bb3c52c7d7b1c93a0f9aea86688eba14e4f79
size 50331
oid sha256:cdef08ee53dcd8b6ba7f599e6264b17ca23add1cc0c824d5bb01ba033223920c
size 70563

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:57e926d66d843ae875930a5625cd7fbf3ec73d2fced400cc476ba2d5e30e456e
size 70109
oid sha256:9cdf64b4ce3eedf3b3c9dc78adecf093d562dd839ff94b34550602592d77f6ad
size 89304

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c2397e68ef6f1666a4b8da11d2a84306a3bd162e0464cc1d3c344eee39cb58db
size 73528
oid sha256:96b19939706086621b14c3b28dc7cc6cff5f92363f241e4efd907cbc82aa1ef1
size 145495

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:49badfad4daefe3f88eb85716cde43a3a7e81587b61d7f27551cee2d8c7c3134
size 62528
oid sha256:d5bfb165c7566fa93c490d775c4d1ce1eed9a78bf78ad2ff7e3029e48684cca1
size 99065

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:aa050f41d2c83f5d441011ac88a47680913f1489dcc47500d816ce797531a0e3
size 98235
oid sha256:c08b79a27496e4c14e6a20b3dcc986cd4ac028ad9fbc1560ce331b3b03b1f9c6
size 135286

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:66bf3b99fa39402357a04ebc6d403e77d5aea8cb89022f15506eb0ef64fe65ec
size 166144
oid sha256:19c22b28087c5d9e3ebbde646f9acea9eeb522b4cd472728866ff55eb1f5560e
size 165392

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e3e2262a9b8752607b64d5e96a999eb5667c5dd4506f3be1374c59054a4fece5
size 174257
oid sha256:7f368c979f72fd2b11236d6dc38bf14ea7a3ea1659a50017678f95a97ef31813
size 173122

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1062bd3adf6d606bb0d1f8c693bff1e66ae6110e0bf5a6f65037f2b980e6e39e
size 111198
oid sha256:3becfb5155931fcb110b31ab68ae8079223eb5465094e77a54ab8dd04b0f7a57
size 110465

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1a3e452e09cb3ab4908ad93c1802ceae66dc60334a2494fce8c34ea58bc2ab7e
size 127950
oid sha256:8888662b7e7502bf76b721a09e4a978a44d8b9cad0384b19d642074e4a9101b2
size 126872