Skip to content

Commit

Permalink
Build edit item screen (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
KatherineInCode authored Apr 12, 2024
1 parent f0d3c17 commit 4f6f2e8
Show file tree
Hide file tree
Showing 20 changed files with 1,049 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// Defines the hash algorithms supported for TOTP.
///
enum TOTPCryptoHashAlgorithm: String {
enum TOTPCryptoHashAlgorithm: String, Menuable, CaseIterable {
case sha1 = "SHA1"
case sha256 = "SHA256"
case sha512 = "SHA512"
Expand All @@ -18,4 +18,8 @@ enum TOTPCryptoHashAlgorithm: String {
self = .sha1
}
}

var localizedName: String {
rawValue
}
}
15 changes: 15 additions & 0 deletions AuthenticatorShared/Core/Vault/Services/TOTP/TOTPKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ enum TOTPKey: Equatable {

// MARK: Properties

/// The account name for the TOTP code.
/// Only works for `otpAuthUri` types.
var accountName: String? {
guard case let .otpAuthUri(model) = self else { return nil }
return model.accountName
}

/// The hash algorithm used for the TOTP code.
/// For `otpAuthUri`, it extracts the algorithm from the model.
/// Defaults to SHA1 for other types.
Expand All @@ -35,6 +42,14 @@ enum TOTPKey: Equatable {
}
}

/// The issuer for the TOTP code.
/// Only works for `otpAuthUri` types.
var issuer: String? {
guard case let .otpAuthUri(model) = self else { return nil }
return model.issuer
}


/// The key used for generating the TOTP code.
/// Directly returns the key for base32 and Steam URI.
/// For `otpAuthUri`, extracts the key from the model.
Expand Down
17 changes: 13 additions & 4 deletions AuthenticatorShared/Core/Vault/Services/TOTP/TOTPKeyModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
public struct TOTPKeyModel: Equatable, Sendable {
// MARK: Properties

/// The account name of the TOTP code.
let accountName: String?

/// The hash algorithm used for the TOTP code.
///
let algorithm: TOTPCryptoHashAlgorithm
Expand All @@ -16,6 +19,9 @@ public struct TOTPKeyModel: Equatable, Sendable {
///
let digits: Int

/// The issuer of the TOTP code.
let issuer: String?

/// The time period (in seconds) for which the TOTP code is valid.
///
let period: Int
Expand All @@ -31,12 +37,15 @@ public struct TOTPKeyModel: Equatable, Sendable {
/// Initializes a new configuration from an authenticator key.
///
/// - Parameter authenticatorKey: A string representing the TOTP key.
init?(authenticatorKey: String) {
guard let keyType = TOTPKey(authenticatorKey) else { return nil }
init?(authenticatorKey: String?) {
guard let authenticatorKey = authenticatorKey,
let keyType = TOTPKey(authenticatorKey) else { return nil }
rawAuthenticatorKey = authenticatorKey
totpKey = keyType
period = keyType.period
digits = keyType.digits
accountName = keyType.accountName
algorithm = keyType.algorithm
digits = keyType.digits
issuer = keyType.issuer
period = keyType.period
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "down-angle.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "up-angle.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@
"TenSeconds" = "10 seconds";
"ThirtySeconds" = "30 seconds";
"TwentySeconds" = "20 seconds";
"SixtySeconds" = "60 seconds";
"NinetySeconds" = "90 seconds";
"TwoMinutes" = "2 minutes";
"ClearClipboard" = "Clear clipboard";
"ClearClipboardDescription" = "Automatically clear copied values from your clipboard.";
Expand Down Expand Up @@ -880,3 +882,4 @@
"Duo" = "Duo";
"DuoUnsupported" = "Duo not yet supported.";
"Issuer" = "Issuer";
"Advanced" = "Advanced";
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import SwiftUI

// MARK: - FormMenuField

/// The data necessary for displaying a `FormMenuFieldView`.
///
struct FormMenuField<State, T: Menuable>: Equatable, Identifiable {
// MARK: Properties

/// The accessibility identifier to apply to the field.
let accessibilityIdentifier: String?

/// The footer text displayed below the menu field.
let footer: String?

/// A key path for updating the backing value for the menu field.
let keyPath: WritableKeyPath<State, T>

/// The options displayed in the menu.
let options: [T]

/// The current selection.
let selection: T

/// The title of the field.
let title: String

// MARK: Identifiable

var id: String {
"FormMenuField-\(title)"
}

// MARK: Initialization

/// Initialize a `FormMenuField`.
///
/// - Parameters:
/// - accessibilityIdentifier: The accessibility identifier given to the menu field.
/// - footer: The footer text displayed below the menu field.
/// - keyPath: A key path for updating the backing value for the menu field.
/// - options: The options displayed in the menu.
/// - selection: The current selection.
/// - title: The title of the field.
init(
accessibilityIdentifier: String?,
footer: String? = nil,
keyPath: WritableKeyPath<State, T>,
options: [T],
selection: T,
title: String
) {
self.accessibilityIdentifier = accessibilityIdentifier
self.footer = footer
self.keyPath = keyPath
self.options = options
self.selection = selection
self.title = title
}
}

// MARK: - FormMenuFieldView

/// A view that displays a menu field for display in a form.
///
struct FormMenuFieldView<State, T: Menuable, TrailingContent: View>: View {
// MARK: Properties

/// A closure containing the action to take when the menu selection is changed.
let action: (T) -> Void

/// The data for displaying the field.
let field: FormMenuField<State, T>

/// Optional content view that is displayed to the right of the menu value.
let trailingContent: TrailingContent

// MARK: View

var body: some View {
BitwardenMenuField(
title: field.title,
footer: field.footer,
accessibilityIdentifier: field.accessibilityIdentifier,
options: field.options,
selection: Binding(get: { field.selection }, set: action),
trailingContent: { trailingContent }
)
}

// MARK: Initialization

/// Initialize a `FormMenuFieldView`.
///
/// - Parameters:
/// - field: The data for displaying the field.
/// - action: A closure containing the action to take when the menu selection is changed.
///
init(
field: FormMenuField<State, T>,
action: @escaping (T) -> Void
) where TrailingContent == EmptyView {
self.action = action
self.field = field
trailingContent = EmptyView()
}

/// Initialize a `FormMenuFieldView`.
///
/// - Parameters:
/// - field: The data for displaying the field.
/// - action: A closure containing the action to take when the menu selection is changed.
/// - trailingContent: Optional content view that is displayed to the right of the menu value.
///
init(
field: FormMenuField<State, T>,
action: @escaping (T) -> Void,
trailingContent: @escaping () -> TrailingContent
) {
self.action = action
self.field = field
self.trailingContent = trailingContent()
}
}
Loading

0 comments on commit 4f6f2e8

Please sign in to comment.