Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build edit item screen #23

Merged
merged 2 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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