Tweak the flow for disabling key storage. (#3464)

* Refactor RoundedLabelItem into the Compound VisualListItem component.

* Update the design of SecureBackupKeyBackupScreen.

* Add a hint to the key storage toggle when disabled.
This commit is contained in:
Doug
2024-10-29 17:39:55 +00:00
committed by GitHub
parent c11e49f962
commit 368226fd57
33 changed files with 107 additions and 102 deletions
@@ -24,11 +24,11 @@ enum ListPosition {
}
}
struct RoundedLabelItem<Icon: View>: View {
struct VisualListItem<Icon: View>: View {
@Environment(\.backgroundStyle) private var backgroundStyle
let title: String
let listPosition: ListPosition
let position: ListPosition
let iconContent: () -> Icon
private var backgroundColor: AnyShapeStyle {
@@ -39,17 +39,17 @@ struct RoundedLabelItem<Icon: View>: View {
Label { Text(title) } icon: {
iconContent()
}
.labelStyle(CheckmarkLabelStyle())
.padding(.horizontal, 20)
.labelStyle(VisualListItemLabelStyle())
.padding(.horizontal, 16)
.padding(.vertical, 12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(backgroundColor, in: RoundedCornerShape(radius: 16, corners: listPosition.roundedCorners))
.background(backgroundColor, in: RoundedCornerShape(radius: 14, corners: position.roundedCorners))
}
}
private struct CheckmarkLabelStyle: LabelStyle {
private struct VisualListItemLabelStyle: LabelStyle {
func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .top, spacing: 16) {
HStack(alignment: .top, spacing: 12) {
configuration.icon
configuration.title
}
@@ -60,7 +60,7 @@ private struct CheckmarkLabelStyle: LabelStyle {
// MARK: - Previews
struct AnalyticsPromptScreenCheckmarkItem_Previews: PreviewProvider, TestablePreview {
struct VisualListItem_Previews: PreviewProvider, TestablePreview {
static let strings = AnalyticsPromptScreenStrings(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL)
@ViewBuilder
@@ -75,17 +75,17 @@ struct AnalyticsPromptScreenCheckmarkItem_Previews: PreviewProvider, TestablePre
static var previews: some View {
VStack(alignment: .leading, spacing: 4) {
RoundedLabelItem(title: strings.point1, listPosition: .top) {
VisualListItem(title: strings.point1, position: .top) {
testImage1
}
RoundedLabelItem(title: strings.point2, listPosition: .middle) {
VisualListItem(title: strings.point2, position: .middle) {
testImage2
}
RoundedLabelItem(title: "This is a short string.", listPosition: .middle) {
VisualListItem(title: "This is a short string.", position: .middle) {
testImage1
}
RoundedLabelItem(title: "This is a very long string that will be used to test the layout over multiple lines of text to ensure everything is correct.",
listPosition: .bottom) {
VisualListItem(title: "This is a very long string that will be used to test the layout over multiple lines of text to ensure everything is correct.",
position: .bottom) {
testImage2
}
}
@@ -70,7 +70,7 @@ struct EncryptionResetScreen: View {
@ViewBuilder
private func checkMarkItem(title: String, position: ListPosition, positive: Bool) -> some View {
RoundedLabelItem(title: title, listPosition: position) {
VisualListItem(title: title, position: position) {
CompoundIcon(positive ? \.check : \.info)
.foregroundColor(positive ? .compound.iconAccentPrimary : .compound.iconSecondary)
.alignmentGuide(.top) { _ in 2 }
@@ -65,7 +65,7 @@ struct AnalyticsPromptScreen: View {
@ViewBuilder
private func checkMarkItem(title: String, position: ListPosition) -> some View {
RoundedLabelItem(title: title, listPosition: position) {
VisualListItem(title: title, position: position) {
CompoundIcon(\.checkCircle, size: .small, relativeTo: .body)
.foregroundColor(.compound.iconAccentPrimary)
}
@@ -39,37 +39,37 @@ struct SecureBackupKeyBackupScreen: View {
}
private var disableBackupSection: some View {
VStack(spacing: 16) {
BigIcon(icon: \.keyOffSolid)
Text(L10n.screenKeyBackupDisableTitle)
.foregroundColor(.compound.textPrimary)
.font(.compound.headingMDBold)
.multilineTextAlignment(.center)
Text(L10n.screenKeyBackupDisableDescription)
.foregroundColor(.compound.textSecondary)
.font(.compound.bodyMD)
.multilineTextAlignment(.center)
VStack(alignment: .leading, spacing: 10) {
Label {
Text(L10n.screenKeyBackupDisableDescriptionPoint1)
.foregroundColor(.compound.textSecondary)
.font(.compound.bodyMD)
} icon: {
CompoundIcon(\.close)
.foregroundColor(.compound.iconCriticalPrimary)
}
VStack(spacing: 24) {
VStack(spacing: 16) {
BigIcon(icon: \.error, style: .alertSolid)
Label {
Text(L10n.screenKeyBackupDisableDescriptionPoint2(InfoPlistReader.main.bundleDisplayName))
VStack(spacing: 8) {
Text(L10n.screenKeyBackupDisableTitle)
.foregroundColor(.compound.textPrimary)
.font(.compound.headingMDBold)
.multilineTextAlignment(.center)
Text(L10n.screenKeyBackupDisableDescription)
.foregroundColor(.compound.textSecondary)
.font(.compound.bodyMD)
} icon: {
CompoundIcon(\.close)
.multilineTextAlignment(.center)
}
}
VStack(alignment: .leading, spacing: 4) {
VisualListItem(title: L10n.screenKeyBackupDisableDescriptionPoint1,
position: .top) {
CompoundIcon(\.close, size: .small, relativeTo: .body)
.foregroundColor(.compound.iconCriticalPrimary)
}
.backgroundStyle(.compound.bgActionSecondaryHovered)
VisualListItem(title: L10n.screenKeyBackupDisableDescriptionPoint2(InfoPlistReader.main.productionAppName),
position: .bottom) {
CompoundIcon(\.close, size: .small, relativeTo: .body)
.foregroundColor(.compound.iconCriticalPrimary)
}
.backgroundStyle(.compound.bgActionSecondaryHovered)
}
}
}
@@ -17,6 +17,10 @@ struct SecureBackupScreenViewState: BindableState {
var recoveryState = SecureBackupRecoveryState.unknown
var keyBackupState = SecureBackupKeyBackupState.unknown
var bindings: SecureBackupScreenViewStateBindings
var keyStorageToggleDescription: String? {
keyBackupState.keyStorageToggleState ? nil : L10n.screenChatBackupKeyStorageDisabledError
}
}
struct SecureBackupScreenViewStateBindings {
@@ -26,7 +26,7 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
self.userIndicatorController = userIndicatorController
super.init(initialViewState: .init(chatBackupDetailsURL: chatBackupDetailsURL,
bindings: SecureBackupScreenViewStateBindings(keyStorageEnabled: secureBackupController.keyBackupState.value.toggleState)))
bindings: SecureBackupScreenViewStateBindings(keyStorageEnabled: secureBackupController.keyBackupState.value.keyStorageToggleState)))
secureBackupController.recoveryState
.receive(on: DispatchQueue.main)
@@ -38,7 +38,7 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
.sink { [weak self] state in
guard let self else { return }
self.state.keyBackupState = state
self.state.bindings.keyStorageEnabled = state.toggleState
self.state.bindings.keyStorageEnabled = state.keyStorageToggleState
}
.store(in: &cancellables)
}
@@ -53,10 +53,10 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
let keyBackupState = secureBackupController.keyBackupState.value
switch (keyBackupState, enable) {
case (.unknown, true):
state.bindings.keyStorageEnabled = keyBackupState.toggleState // Reset the toggle in case enabling fails
state.bindings.keyStorageEnabled = keyBackupState.keyStorageToggleState // Reset the toggle in case enabling fails
enableBackup()
case (.enabled, false):
state.bindings.keyStorageEnabled = keyBackupState.toggleState // Reset the toggle in case the user cancels
state.bindings.keyStorageEnabled = keyBackupState.keyStorageToggleState // Reset the toggle in case the user cancels
actionsSubject.send(.keyBackup)
default:
break
@@ -83,8 +83,8 @@ class SecureBackupScreenViewModel: SecureBackupScreenViewModelType, SecureBackup
}
}
private extension SecureBackupKeyBackupState {
var toggleState: Bool {
extension SecureBackupKeyBackupState {
var keyStorageToggleState: Bool {
switch self {
case .unknown, .enabling: false
case .enabled, .disabling: true
@@ -68,7 +68,8 @@ struct SecureBackupScreen: View {
}
private var keyStorageToggle: some View {
ListRow(label: .plain(title: L10n.screenChatBackupKeyStorageToggleTitle),
ListRow(label: .plain(title: L10n.screenChatBackupKeyStorageToggleTitle,
description: context.viewState.keyStorageToggleDescription),
kind: .toggle($context.keyStorageEnabled))
.onChange(of: context.keyStorageEnabled) { _, newValue in
context.send(viewAction: .keyStorageToggled(newValue))